agent_util.lua 2.94 KB

local _M = { }

-- 超时次数
local heartTimeoutCount 		= 0
-- 加速次数
local heartQuickCount 			= 0
-- 上次检查心跳时间
local lastHeartCheckTime		= 0
-- 下次进入定时检查的时间
local nextCheckTime				= 0
-- 心跳误差允许范围
local HEART_BEAT_ERROR_LIMIT 	= 1
-- 最大超时次数
local HEART_TIMEOUT_COUNT_MAX 	= 20
-- 最大加速次数
local HEART_QUICK_COUNT_MAX 	= 5
-- 心跳定时间隔
local HEART_TIMER_INTERVAL 		= 5

local function check_heart_beat(agent, now)
	-- 充值等操作不检查心跳
	local role = agent.role
	if role.ignoreHeartbeat then
		lastHeartCheckTime = now - HEART_TIMER_INTERVAL
		heartTimeoutCount = 0
		return
	end
	if lastHeartCheckTime - now > HEART_TIMER_INTERVAL or
		now - lastHeartCheckTime > HEART_TIMER_INTERVAL then
		heartTimeoutCount = heartTimeoutCount + 1
		if heartTimeoutCount >= HEART_TIMEOUT_COUNT_MAX then
			skynet.error("timeout! then agent will shut down by self", agent.client_fd, role:getProperty("name"), role:getProperty("id"))
			skynet.call(agent.gate_serv, "lua", "kick", agent.client_fd)
			heartTimeoutCount = 0
		end
	else
		heartTimeoutCount = 0
	end
end

local PointDataMark = {}
local resetTimeStr = string.format("%02d00", RESET_TIME)

local function check_daily_reset(agent, now)
	local date = os.date("*t", now)
	local timeStr = string.format("%02d%02d", date.hour, date.min)
	local dataStr = date.year .. string.format("%02d", date.month) .. string.format("%02d", date.day)

	local function timeEffect(checkTimeStr)
		if timeStr ~= checkTimeStr then
			return false
		end
		if PointDataMark[dataStr] and PointDataMark[dataStr][checkTimeStr] then
			return false
		end
		PointDataMark[dataStr] = PointDataMark[dataStr] or {}
		PointDataMark[dataStr][checkTimeStr] = true
		return true
	end

	if timeEffect(resetTimeStr) then
		-- 刷新每日数据
		local role = agent.role
		if role then
			role:onCrossDay(now, true)
		end
	end
end

function _M:update(agent)
	local now = skynet.timex()
	local role = agent.role
	if now >= nextCheckTime then
		pcall(check_heart_beat, agent, now)
		nextCheckTime = now + HEART_TIMER_INTERVAL
	end
	pcall(check_daily_reset, agent, now)
	pcall(role.onRecoverTimer, role, now)
end

function _M:heart_beat(agent)
	local now = skynet.timex()
	if now == lastHeartCheckTime then
		return
	end
	if now - lastHeartCheckTime <= HEART_TIMER_INTERVAL - HEART_BEAT_ERROR_LIMIT then
		heartQuickCount = heartQuickCount + 1
		if heartQuickCount == HEART_QUICK_COUNT_MAX then
			-- 将错误写入日志
			local role = agent.role
			skynet.error("Warning, heart beating is too quick, shut down the agent", agent.client_fd, role:getProperty("name"), role:getProperty("id"))
			-- skynet.call(agent.gate_serv, "lua", "kick", agent.client_fd)
			role:warningHeartTooQuick()
			heartQuickCount = 0
		end
	else
		heartQuickCount = 0
	end
	lastHeartCheckTime = now
end

function _M:reset()
	heartTimeoutCount = 0
	heartQuickCount = 0
	lastHeartCheckTime = skynet.timex()
end

return _M