mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-25 12:43:09 +00:00
add skynet.response for delay response
This commit is contained in:
@@ -14,7 +14,7 @@ local function monitor(name, obj, cobj)
|
||||
while true do
|
||||
newobj = skynet.call(service, "lua", "monitor", name, newobj)
|
||||
if newobj == nil then
|
||||
return
|
||||
break
|
||||
end
|
||||
sd.update(obj, newobj)
|
||||
end
|
||||
|
||||
@@ -43,12 +43,14 @@ end
|
||||
local session_id_coroutine = {}
|
||||
local session_coroutine_id = {}
|
||||
local session_coroutine_address = {}
|
||||
local session_response = {}
|
||||
|
||||
local wakeup_session = {}
|
||||
local sleep_session = {}
|
||||
|
||||
local watching_service = {}
|
||||
local watching_session = {}
|
||||
local dead_service = {}
|
||||
local error_queue = {}
|
||||
|
||||
-- suspend is function
|
||||
@@ -73,7 +75,9 @@ local function _error_dispatch(error_session, error_source)
|
||||
if error_session == 0 then
|
||||
-- service is down
|
||||
-- Don't remove from watching_service , because user may call dead service
|
||||
watching_service[error_source] = false
|
||||
if watching_service[error_source] then
|
||||
dead_service[error_source] = true
|
||||
end
|
||||
for session, srv in pairs(watching_session) do
|
||||
if srv == error_source then
|
||||
table.insert(error_queue, session)
|
||||
@@ -122,6 +126,18 @@ local function dispatch_wakeup()
|
||||
end
|
||||
end
|
||||
|
||||
local function release_watching(address)
|
||||
local ref = watching_service[address]
|
||||
if ref then
|
||||
ref = ref - 1
|
||||
if ref > 0 then
|
||||
watching_service[address] = ref
|
||||
else
|
||||
watching_service[address] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- suspend is local function
|
||||
function suspend(co, result, command, param, size)
|
||||
if not result then
|
||||
@@ -142,15 +158,50 @@ function suspend(co, result, command, param, size)
|
||||
elseif command == "RETURN" then
|
||||
local co_session = session_coroutine_id[co]
|
||||
local co_address = session_coroutine_address[co]
|
||||
if param == nil then
|
||||
if param == nil or session_response[co] then
|
||||
error(debug.traceback(co))
|
||||
end
|
||||
c.send(co_address, skynet.PTYPE_RESPONSE, co_session, param, size)
|
||||
return suspend(co, coroutine.resume(co))
|
||||
session_response[co] = true
|
||||
local ret
|
||||
if not dead_service[co_address] then
|
||||
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, param, size) >= 0
|
||||
elseif size == nil then
|
||||
c.trash(param, size)
|
||||
ret = false
|
||||
end
|
||||
return suspend(co, coroutine.resume(co, ret))
|
||||
elseif command == "RESPONSE" then
|
||||
local co_session = session_coroutine_id[co]
|
||||
local co_address = session_coroutine_address[co]
|
||||
if session_response[co] then
|
||||
error(debug.traceback(co))
|
||||
end
|
||||
local f = param
|
||||
local function response(ok, ...)
|
||||
local ret
|
||||
if not dead_service[co_address] then
|
||||
if ok then
|
||||
ret = c.send(co_address, skynet.PTYPE_RESPONSE, co_session, f(...)) >=0
|
||||
else
|
||||
ret = c.send(co_address, skynet.PTYPE_ERROR, co_session, "") >=0
|
||||
end
|
||||
else
|
||||
ret = false
|
||||
end
|
||||
release_watching(co_address)
|
||||
f = nil
|
||||
return ret
|
||||
end
|
||||
watching_service[co_address] = watching_service[co_address] + 1
|
||||
session_response[co] = response
|
||||
return suspend(co, coroutine.resume(co, response))
|
||||
elseif command == "EXIT" then
|
||||
-- coroutine exit
|
||||
local address = session_coroutine_address[co]
|
||||
release_watching(address)
|
||||
session_coroutine_id[co] = nil
|
||||
session_coroutine_address[co] = nil
|
||||
session_response[co] = nil
|
||||
elseif command == "QUIT" then
|
||||
-- service exit
|
||||
return
|
||||
@@ -259,13 +310,21 @@ end
|
||||
|
||||
function skynet.exit()
|
||||
skynet.send(".launcher","lua","REMOVE",skynet.self())
|
||||
-- report the sources that call me
|
||||
for co, session in pairs(session_coroutine_id) do
|
||||
local address = session_coroutine_address[co]
|
||||
local self = skynet.self()
|
||||
if session~=0 and address then
|
||||
skynet.redirect(address, self, "error", session, "")
|
||||
c.redirect(address, 0, skynet.PTYPE_ERROR, session, "")
|
||||
end
|
||||
end
|
||||
-- report the sources I call but haven't return
|
||||
local tmp = {}
|
||||
for session, address in pairs(watching_session) do
|
||||
tmp[address] = true
|
||||
end
|
||||
for address in pairs(tmp) do
|
||||
c.redirect(address, 0, skynet.PTYPE_ERROR, 0, "")
|
||||
end
|
||||
c.command("EXIT")
|
||||
-- quit service
|
||||
coroutine_yield "QUIT"
|
||||
@@ -294,9 +353,6 @@ end
|
||||
|
||||
function skynet.send(addr, typename, ...)
|
||||
local p = proto[typename]
|
||||
if watching_service[addr] == false then
|
||||
error("Service is dead")
|
||||
end
|
||||
return c.send(addr, p.id, 0 , p.pack(...))
|
||||
end
|
||||
|
||||
@@ -321,9 +377,6 @@ end
|
||||
|
||||
function skynet.call(addr, typename, ...)
|
||||
local p = proto[typename]
|
||||
if watching_service[addr] == false then
|
||||
error("Service is dead")
|
||||
end
|
||||
local session = c.send(addr, p.id , nil , p.pack(...))
|
||||
if session == nil then
|
||||
error("call to invalid address " .. skynet.address(addr))
|
||||
@@ -333,16 +386,18 @@ end
|
||||
|
||||
function skynet.rawcall(addr, typename, msg, sz)
|
||||
local p = proto[typename]
|
||||
if watching_service[addr] == false then
|
||||
error("Service is dead")
|
||||
end
|
||||
local session = assert(c.send(addr, p.id , nil , msg, sz), "call to invalid address")
|
||||
return yield_call(addr, session)
|
||||
end
|
||||
|
||||
function skynet.ret(msg, sz)
|
||||
msg = msg or ""
|
||||
coroutine_yield("RETURN", msg, sz)
|
||||
return coroutine_yield("RETURN", msg, sz)
|
||||
end
|
||||
|
||||
function skynet.response(pack)
|
||||
pack = pack or skynet.pack
|
||||
return coroutine_yield("RESPONSE", pack)
|
||||
end
|
||||
|
||||
function skynet.retpack(...)
|
||||
@@ -412,6 +467,12 @@ local function raw_dispatch_message(prototype, msg, sz, session, source, ...)
|
||||
local p = assert(proto[prototype], prototype)
|
||||
local f = p.dispatch
|
||||
if f then
|
||||
local ref = watching_service[source]
|
||||
if ref then
|
||||
watching_service[source] = ref + 1
|
||||
else
|
||||
watching_service[source] = 1
|
||||
end
|
||||
local co = co_create(f)
|
||||
session_coroutine_id[co] = session
|
||||
session_coroutine_address[co] = source
|
||||
|
||||
Reference in New Issue
Block a user