原本 dispatch_by_order 循环中,socket.block 方法是挂起协程阻塞的,当客户端socket主动断开的时候,socket 协程被唤醒发现 connected 为 false,继续执行了 close_channel_socket(self) 和 wakeup_all(self),进而调用 socket.close 关闭了 socket 。所以,channel:request 中的_block_connect_ 方法 check_connection 返回false,执行了相关的重连逻辑。更新版本后,dispatch_by_order 循环中不处理客户端 socket 主动关闭,从而 channel:request 中_block_connect_ 方法 check_connection 返回true,重连逻辑没有被执行,直接在已经断开的 socket 上执行 write 方法报错,报错之后 socket 关闭标识会被更新,所以在下一次执行_channel:request_ 的时候,重连逻辑会被触发运行。
我的处理比较粗暴,如果请求失败,执行一次SELECT 1, 这时重连是成功的,然后再执行之前的失败请求
@LokerLi 提供的方法,SELECT 1,会触发socketchannel报错并更新_socket.__closed_标识,再执行正式的请求就会重连返回正确的消息了。 我们现在采取的方式是pcall调用数据库查询方法,如果报错再执行一遍。
local CMD = {}
local pool = {}
local size = 10
local index = 1
local function getdb()
local db = pool[index]
index = index + 1
if index > size then
index = 1
end
return db
end
function CMD.query(sql)
local db = getdb()
local ok, result = pcall(db.query, db, sql)
print(ok, result)
if not ok then
result = db:query(sql)
end
print(dump(result))
return result
end
可是项目遇到的问题是,更新skynet版本后,每天早上mysql的query方法都会报错,并且一直没有重连成功。因为处于测试阶段,所以晚上并没有活动的数据库连接,wait_timeout的超时时间过了后,数据库连接就断开了。我猜测是这个样子,但是为什么不能重连成功呢?
后来确认是mysql断开确实是因为wait_timeout默认为8小时,项目开发阶段晚上并没有活动的数据库连接,所以早上上班测试的发现连接已经断开。一直没有被发现的原因,是因为以前sockectchannel自动重连。又因为采用了100大小的连接池,所以错认为一直重连不成功,只是没有在一个连接中重复请求罢了。
经测试,redis断开之后,也是第二次才能重连成功。
@cloudwu 云大,不清楚当初那个patch [bugfix: socketchannel order mode may blocked. (used by redis driver)] 的修改初衷是为了什么,难道现在重连必须二次才能成功吗?还是我的理解有错误,希望你能指点一二。