Improve socketchannel, try the next host in backup list when auth failed. See issue #1145

This commit is contained in:
Cloud Wu
2020-01-10 09:38:07 +08:00
committed by 云风
parent d3a6b8d80b
commit da4360787f
2 changed files with 118 additions and 108 deletions

View File

@@ -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
else elseif rs_data.primary then
if rs_data.primary then
local host, port = __parse_addr(rs_data.primary) local host, port = __parse_addr(rs_data.primary)
mongoc.host = host mongoc.host = host
mongoc.port = port mongoc.port = port
mongoc.__sock:changehost(host, port) mongoc.__sock:changehost(host, port)
else else
skynet.error("WARNING: NO PRIMARY RETURN " .. rs_data.me) -- socketchannel would try the next host in backup list
-- determine the primary db using hosts error ("No primary return : " .. tostring(rs_data.me))
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

View File

@@ -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,17 +212,57 @@ local function connect_once(self)
if self.__closed then if self.__closed then
return false return false
end end
local addr_list = {}
local addr_set = {}
local function _add_backup()
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
-- don't add the same host
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
local function _next_addr()
local addr = table.remove(addr_list,1)
if addr then
skynet.error("socket: connect to backup host", addr.host, addr.port)
end
return addr
end
local function _connect_once(self, addr)
local fd,err = socket.open(addr.host, addr.port)
if not fd then
-- try next one
addr = _next_addr()
if addr == nil then
return false, err
end
return _connect_once(self, addr)
end
self.__host = addr.host
self.__port = addr.port
assert(not self.__sock and not self.__authcoroutine) assert(not self.__sock and not self.__authcoroutine)
-- term current dispatch thread (send a signal) -- term current dispatch thread (send a signal)
term_dispatch_thread(self) term_dispatch_thread(self)
local fd,err = socket.open(self.__host, self.__port)
if not fd then
fd = connect_backup(self)
if not fd then
return false, err
end
end
if self.__nodelay then if self.__nodelay then
socketdriver.nodelay(fd) socketdriver.nodelay(fd)
end end
@@ -297,14 +316,28 @@ local function connect_once(self)
end end
end end
self.__authcoroutine = false self.__authcoroutine = false
if ok and not self.__sock then if ok then
if not self.__sock then
-- auth may change host, so connect again -- auth may change host, so connect again
return connect_once(self) return connect_once(self)
end end
return ok -- 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
return true return true
end
_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)