mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-25 04:33:05 +00:00
Improve socketchannel, try the next host in backup list when auth failed. See issue #1145
This commit is contained in:
@@ -112,38 +112,15 @@ local function mongo_auth(mongoc)
|
|||||||
mongoc.__sock:changebackup(backup)
|
mongoc.__sock:changebackup(backup)
|
||||||
end
|
end
|
||||||
if rs_data.ismaster then
|
if rs_data.ismaster then
|
||||||
if rawget(mongoc, "__pickserver") then
|
|
||||||
rawset(mongoc, "__pickserver", nil)
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
|
elseif rs_data.primary then
|
||||||
|
local host, port = __parse_addr(rs_data.primary)
|
||||||
|
mongoc.host = host
|
||||||
|
mongoc.port = port
|
||||||
|
mongoc.__sock:changehost(host, port)
|
||||||
else
|
else
|
||||||
if rs_data.primary then
|
-- socketchannel would try the next host in backup list
|
||||||
local host, port = __parse_addr(rs_data.primary)
|
error ("No primary return : " .. tostring(rs_data.me))
|
||||||
mongoc.host = host
|
|
||||||
mongoc.port = port
|
|
||||||
mongoc.__sock:changehost(host, port)
|
|
||||||
else
|
|
||||||
skynet.error("WARNING: NO PRIMARY RETURN " .. rs_data.me)
|
|
||||||
-- determine the primary db using hosts
|
|
||||||
local pickserver = {}
|
|
||||||
if rawget(mongoc, "__pickserver") == nil then
|
|
||||||
for _, v in ipairs(rs_data.hosts) do
|
|
||||||
if v ~= rs_data.me then
|
|
||||||
table.insert(pickserver, v)
|
|
||||||
end
|
|
||||||
rawset(mongoc, "__pickserver", pickserver)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #mongoc.__pickserver <= 0 then
|
|
||||||
error("CAN NOT DETERMINE THE PRIMARY DB")
|
|
||||||
end
|
|
||||||
skynet.error("INFO: TRY TO CONNECT " .. mongoc.__pickserver[1])
|
|
||||||
local host, port = __parse_addr(mongoc.__pickserver[1])
|
|
||||||
table.remove(mongoc.__pickserver, 1)
|
|
||||||
mongoc.host = host
|
|
||||||
mongoc.port = port
|
|
||||||
mongoc.__sock:changehost(host, port)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -201,27 +201,6 @@ local function dispatch_function(self)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function connect_backup(self)
|
|
||||||
if self.__backup then
|
|
||||||
for _, addr in ipairs(self.__backup) do
|
|
||||||
local host, port
|
|
||||||
if type(addr) == "table" then
|
|
||||||
host, port = addr.host, addr.port
|
|
||||||
else
|
|
||||||
host = addr
|
|
||||||
port = self.__port
|
|
||||||
end
|
|
||||||
skynet.error("socket: connect to backup host", host, port)
|
|
||||||
local fd = socket.open(host, port)
|
|
||||||
if fd then
|
|
||||||
self.__host = host
|
|
||||||
self.__port = port
|
|
||||||
return fd
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function term_dispatch_thread(self)
|
local function term_dispatch_thread(self)
|
||||||
if not self.__response and self.__dispatch_thread then
|
if not self.__response and self.__dispatch_thread then
|
||||||
-- dispatch by order, send close signal to dispatch thread
|
-- dispatch by order, send close signal to dispatch thread
|
||||||
@@ -233,78 +212,132 @@ local function connect_once(self)
|
|||||||
if self.__closed then
|
if self.__closed then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
assert(not self.__sock and not self.__authcoroutine)
|
|
||||||
-- term current dispatch thread (send a signal)
|
|
||||||
term_dispatch_thread(self)
|
|
||||||
|
|
||||||
local fd,err = socket.open(self.__host, self.__port)
|
local addr_list = {}
|
||||||
if not fd then
|
local addr_set = {}
|
||||||
fd = connect_backup(self)
|
|
||||||
if not fd then
|
|
||||||
return false, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if self.__nodelay then
|
|
||||||
socketdriver.nodelay(fd)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- register overload warning
|
local function _add_backup()
|
||||||
|
if self.__backup then
|
||||||
local overload = self.__overload_notify
|
for _, addr in ipairs(self.__backup) do
|
||||||
if overload then
|
local host, port
|
||||||
local function overload_trigger(id, size)
|
if type(addr) == "table" then
|
||||||
if id == self.__sock[1] then
|
host,port = addr.host, addr.port
|
||||||
if size == 0 then
|
|
||||||
if self.__overload then
|
|
||||||
self.__overload = false
|
|
||||||
overload(false)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
if not self.__overload then
|
host = addr
|
||||||
self.__overload = true
|
port = self.__port
|
||||||
overload(true)
|
end
|
||||||
else
|
|
||||||
skynet.error(string.format("WARNING: %d K bytes need to send out (fd = %d %s:%s)", size, id, self.__host, self.__port))
|
-- don't add the same host
|
||||||
end
|
local hostkey = host..":"..port
|
||||||
|
if not addr_set[hostkey] then
|
||||||
|
addr_set[hostkey] = true
|
||||||
|
table.insert(addr_list, { host = host, port = port })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
skynet.fork(overload_trigger, fd, 0)
|
|
||||||
socket.warning(fd, overload_trigger)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
while self.__dispatch_thread do
|
local function _next_addr()
|
||||||
-- wait for dispatch thread exit
|
local addr = table.remove(addr_list,1)
|
||||||
skynet.yield()
|
if addr then
|
||||||
|
skynet.error("socket: connect to backup host", addr.host, addr.port)
|
||||||
|
end
|
||||||
|
return addr
|
||||||
end
|
end
|
||||||
|
|
||||||
self.__sock = setmetatable( {fd} , channel_socket_meta )
|
local function _connect_once(self, addr)
|
||||||
self.__dispatch_thread = skynet.fork(function()
|
local fd,err = socket.open(addr.host, addr.port)
|
||||||
pcall(dispatch_function(self), self)
|
if not fd then
|
||||||
-- clear dispatch_thread
|
-- try next one
|
||||||
self.__dispatch_thread = nil
|
addr = _next_addr()
|
||||||
end)
|
if addr == nil then
|
||||||
|
return false, err
|
||||||
|
end
|
||||||
|
return _connect_once(self, addr)
|
||||||
|
end
|
||||||
|
|
||||||
if self.__auth then
|
self.__host = addr.host
|
||||||
self.__authcoroutine = coroutine.running()
|
self.__port = addr.port
|
||||||
local ok , message = pcall(self.__auth, self)
|
|
||||||
if not ok then
|
assert(not self.__sock and not self.__authcoroutine)
|
||||||
close_channel_socket(self)
|
-- term current dispatch thread (send a signal)
|
||||||
if message ~= socket_error then
|
term_dispatch_thread(self)
|
||||||
self.__authcoroutine = false
|
|
||||||
skynet.error("socket: auth failed", message)
|
if self.__nodelay then
|
||||||
|
socketdriver.nodelay(fd)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- register overload warning
|
||||||
|
|
||||||
|
local overload = self.__overload_notify
|
||||||
|
if overload then
|
||||||
|
local function overload_trigger(id, size)
|
||||||
|
if id == self.__sock[1] then
|
||||||
|
if size == 0 then
|
||||||
|
if self.__overload then
|
||||||
|
self.__overload = false
|
||||||
|
overload(false)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not self.__overload then
|
||||||
|
self.__overload = true
|
||||||
|
overload(true)
|
||||||
|
else
|
||||||
|
skynet.error(string.format("WARNING: %d K bytes need to send out (fd = %d %s:%s)", size, id, self.__host, self.__port))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
skynet.fork(overload_trigger, fd, 0)
|
||||||
|
socket.warning(fd, overload_trigger)
|
||||||
|
end
|
||||||
|
|
||||||
|
while self.__dispatch_thread do
|
||||||
|
-- wait for dispatch thread exit
|
||||||
|
skynet.yield()
|
||||||
|
end
|
||||||
|
|
||||||
|
self.__sock = setmetatable( {fd} , channel_socket_meta )
|
||||||
|
self.__dispatch_thread = skynet.fork(function()
|
||||||
|
pcall(dispatch_function(self), self)
|
||||||
|
-- clear dispatch_thread
|
||||||
|
self.__dispatch_thread = nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
if self.__auth then
|
||||||
|
self.__authcoroutine = coroutine.running()
|
||||||
|
local ok , message = pcall(self.__auth, self)
|
||||||
|
if not ok then
|
||||||
|
close_channel_socket(self)
|
||||||
|
if message ~= socket_error then
|
||||||
|
self.__authcoroutine = false
|
||||||
|
skynet.error("socket: auth failed", message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.__authcoroutine = false
|
||||||
|
if ok then
|
||||||
|
if not self.__sock then
|
||||||
|
-- auth may change host, so connect again
|
||||||
|
return connect_once(self)
|
||||||
|
end
|
||||||
|
-- auth succ, go through
|
||||||
|
else
|
||||||
|
-- auth failed, try next addr
|
||||||
|
_add_backup() -- auth may add new backup hosts
|
||||||
|
addr = _next_addr()
|
||||||
|
if addr == nil then
|
||||||
|
return false, "no more backup host"
|
||||||
|
end
|
||||||
|
return _connect_once(self, addr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.__authcoroutine = false
|
|
||||||
if ok and not self.__sock then
|
return true
|
||||||
-- auth may change host, so connect again
|
|
||||||
return connect_once(self)
|
|
||||||
end
|
|
||||||
return ok
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
_add_backup()
|
||||||
|
return _connect_once(self, { host = self.__host, port = self.__port })
|
||||||
end
|
end
|
||||||
|
|
||||||
local function try_connect(self , once)
|
local function try_connect(self , once)
|
||||||
|
|||||||
Reference in New Issue
Block a user