发布事故的原因五花八门,疏漏的环节却高度重合:配置没同步、公告没发、回滚没准备。上线检查单把每次发布的必查项固化为十道关卡——勾完十道再开闸,事故的概率从概率题变成判断题。
---上线检查单:十道关卡逐项过
local CHECKLIST = {
"配置表已全量装载并校验通过",
"数据库变更已在从库预演",
"新增接口已通过协议测试",
"回滚脚本已准备并演练过",
"公告文案已审核并排期",
"补偿方案已确认金额与名单",
"监控告警已覆盖新增功能",
"灰度放量的比例已确认",
"值班人员已知悉发布窗口",
"上一版本的回滚包已归档",
}
function Release.check()
local failed = {}
for i, item in ipairs(CHECKLIST) do
if not Release.verifyItem(i) then
failed[#failed + 1] = i .. ". " .. item
end
end
if #failed > 0 then
Ops.alert("上线检查未通过", table.concat(failed, " | "))
return false
end
Ops.log("十道关卡全部通过,允许发布")
return true
end
十道关卡的执行是逐项机器核验:配置的装载校验、回滚脚本的存在性检查、灰度比例的配置读取——能自动验证的绝不靠人眼,人工只确认机器验不了的(文案的措辞、名单的合理性)。未通过的项目汇总成清单阻断发布,放行的条件是十项全绿。检查单的生命周期:每次事故新增一条对应的检查项,十道关卡会随着教训的积累慢慢变厚——变厚的检查单是团队成熟度的年轮。
---关卡的分档:阻断项与提示项
local LEVELS = { block = {}, warn = {} }
function Release.addItem(text, level, owner)
local bucket = LEVELS[level] or LEVELS.block
bucket[#bucket + 1] = { text = text, owner = owner }
end
---阻断项的零容忍与提示项的宽限
function Release.judge()
if #LEVELS.block > 0 then
Release.blocked(LEVELS.block)
return false
end
if #LEVELS.warn > 0 then
Release.warnList(LEVELS.warn)
end
return true
end
关卡的分档让检查有弹性而不失刚性:阻断项(回滚包缺失、配置校验失败)一票否决,提示项(公告的措辞、文档的更新)记录后放行——分档的边界由事故的复盘驱动调整。检查单的执行人制度:每一关有明确的检查人与签字,发布的责任从模糊集体收敛到具体的人。发布窗口的选择也是关卡之一:避开活动高峰、避开周五下午、避开值班的空档,时间的纪律与代码的纪律同等重要。
检查单的执行率与拦截率的统计:拦截过的真实问题清单是检查单价值的证明;检查的耗时监控,超过 15 分钟的检查流程要优化自动化程度。
检查单曾经纸面化,勾选流于形式,机器可验证的项目全部自动化后形式主义消失。检查项的责任人曾经写团队,出事互相推诿,署名到个人。回滚包的归档曾经靠口头交接,一次回滚时找不到包,归档的自动化与校验补上。
检查单进发布流程的系统化工具,勾选的状态与发布权限联动。每次事故的复盘产出新的检查项,检查单只增不减除非规则过时。新人的第一次发布由老带新,十道关卡的讲解是入职的必修课。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
设计初衷 离线挂机收益不设折损时出现荒诞对比:挂机一周的收益超过手玩三天,勤奋上线变成劣势行为,日常玩法的参与率被自己的离线…
设计初衷 连续登录奖励的断签规则是留存系统的双刃剑:零容忍时,一次出差就清零 29 天连击,玩家的愤怒远超奖励本身的价值;无…
设计初衷 面板战力 50000 的玩家在竞技场打不过 38000 的对手——面板公式与实战表现的偏差超过两成时,玩家的信任崩…
底层原理 全量深拷贝保证整个隔离,但代价随数据规模线性放大:一张 500 键、三层嵌套的配置表,全深拷贝 2.1ms——热路…
底层原理 直接删除(表置 nil、清变量)是不可逆操作:删错一个玩家的邮件配置,找回只能靠备份。软删除把删除拆成两步:先打删…
底层原理 所有异常一股脑 pcall 加严重告警,结果告警系统被“材料不足”这类正常业务拒绝淹没——真正的系统故障反而被噪音…