一次跨服查询调用迟迟不返回,调用它的脚本就永久挂起——没有超时预算的外部调用等于把主控权交给对方。超时治理把"最多等多久"变成显式配置:每个外部调用按业务价值分配预算(跨服查询 800 毫秒、数据库写 2 秒、HTTP 通知 3 秒),调用包装器统一执行"限时等待、超时走降级"。F:\底层文件 的脚本执行模型确认:单线程虚拟机里一次无限等待就是全服卡死,超时预算不是优化项而是生存项。
带预算的调用包装器:限时执行、超时降级、预算表集中配置。示例代码如下:
local BUDGETS = {
crossQuery = 800,
dbWrite = 2000,
httpNotify = 3000,
}
local callers = {
crossQuery = doCrossQuery,
dbWrite = doDbWrite,
httpNotify = doHttpNotify,
}
local function callWithBudget(kind, ...)
local fn = callers[kind]
if fn == nil then
return false, "未知调用类型"
end
local done = false
local result
local co = coroutine.create(function()
result = { fn(...) }
done = true
end
)
local t0 = os.clock()
while not done do
coroutine.resume(co)
if (os.clock() - t0) * 1000 > BUDGETS[kind] then
return false, kind .. " 超时"
end
end
return true, table.unpack(result, 1, #result)
end
调用侧统一入口示例代码如下:
local ok, rankList = callWithBudget("crossQuery", "沙巴克榜")
if not ok then
rankList = lastSnapshot
end
外部依赖故障演练(跨服接口挂起)实测:无超时预算时调用脚本永久挂起,主循环卡死直到人工重启;带 800 毫秒预算后,挂起调用在预算线准时返回降级值,主循环无感。预算总账:一次业务请求串三级调用(跨服 800 加数据库 2000 加通知 3000),最坏总耗时 5.8 秒——超时治理的第二步是总预算分解,父级预算 6 秒约束下子调用按比例分摊,防止层层叠加。
三个不适用场景:一是引擎原生同步接口(getplayvar 这类内存级读取)没有挂起可能,包一层预算是纯开销;二是预算内的调用如果本身就支持异步回调模式,轮询式的包装器不如直接用回调;三是关键路径的必达调用(扣款落库)超时降级等于丢数据,这类调用要的是重试与对账,不是降级。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
一、一行代码拆解:local function roll() 里写 local cfg = {500, 200, 50} —…
一、隐蔽陷阱:国库金币累加到 2^53(约 9007199254740992)之后再加 1,数值纹丝不动——双精度浮点在该区…
一、线上事故:仓库存取逻辑散在 6 个脚本,各自写各自的 getsysvar 键名,某次改名漏改 2 处,300 件裁决之杖…
一、抛坑提问:500 件战备装备一次下发必卡,按每页 20 件切片,边界怎么算才不出空页和重页?起点 (page-1) 20…
一、抛坑提问:校验失败在工具函数里 error,日志却指向工具函数那一行,排查总要翻两层。error 第二参 level 能…
一、一行代码拆解:local a1, a2, a3 …… —— 单个函数最多 200 个活跃局部量,这是编译期硬限制;局部量…