当前位置: 首页 > news >正文

持久化执行前置课(七):崩溃恢复不是重跑,而是先判定已知与未知

上一篇用事务发件箱消除了事件与命令意图之间的双写,但 worker 仍可能停在任意指令。恢复器若只看“最后心跳超时”就重跑,会把暂时卡顿、已完成未回报和真正失联混成一种情况。

一、痛点:超时只说明我们不知道

进程消失前可能尚未领取、正在计算、远端已成功、本地已提交。超时不是失败事实,只是观察者在期限内没有得到新证据。可靠系统应把unknown作为一等状态:纯计算可以重新执行,有幂等回执的活动可以查询或重投,不可查询且不可逆的活动则必须暂停人工核对。

二、原理:恢复决策是一张显式表

恢复输入至少包含租约、活动类别、回执和尝试次数。下面程序把规则写成纯函数,避免散落在异常处理里。相同证据永远产生相同动作,manual_review不会被后台循环偷偷改成重试。

fromdataclassesimportdataclass@dataclass(frozen=True)classEvidence:lease_expired:boolreceipt:str|Noneretry_safe:boolattempts:intmax_attempts:intdefrecover(e:Evidence)->str:ifnote.lease_expired:return"wait"ife.receipt=="succeeded":return"record_completion"ife.receipt=="failed_permanent":return"record_failure"ifnote.retry_safe:return"manual_review"ife.attempts>=e.max_attempts:return"exhausted"return"retry_same_activity"cases=[Evidence(False,None,True,1,3),Evidence(True,"succeeded",True,1,3),Evidence(True,None,False,1,3),Evidence(True,None,True,1,3),]foritemincases:print(recover(item))

输出:

wait record_completion manual_review retry_same_activity

三、实现:租约使用数据库时间和栅栏令牌

仅有租约会遇到旧 worker 复活。每次领取递增fence,提交结果必须携带当前令牌;过期持有者即使恢复,也无法覆盖新持有者。示例用内存对象展示条件更新语义,生产中应放进一个数据库事务。

fromdataclassesimportdataclass@dataclassclassLease:owner:str|None=Noneuntil:int=0fence:int=0result:str|None=Nonedefclaim(lease:Lease,worker:str,now:int,ttl:int)->int:iflease.ownerisnotNoneandlease.until>now:raiseRuntimeError("busy")lease.owner=worker lease.until=now+ttl lease.fence+=1returnlease.fencedefcomplete(lease:Lease,worker:str,fence:int,result:str)->None:iflease.owner!=workerorlease.fence!=fence:raiseRuntimeError("stale_worker")lease.result=result lease=Lease()old=claim(lease,"a",0,5)new=claim(lease,"b",6,5)try:complete(lease,"a",old,"late")exceptRuntimeErroraserror:print(error)complete(lease,"b",new,"ok")print(lease.fence,lease.result)

输出:

stale_worker 2 ok

四、踩坑:心跳不是进度,接管也不是回滚

worker 可以持续心跳却死循环,因此还要记录最后事件序号和活动阶段。反过来,长时间 API 调用没有心跳也未必失败,租约应按活动类型配置并可续期。不要使用各 worker 本地时钟裁决租约;时钟漂移会制造双主,应依赖数据库时间或协调服务。

恢复器不能删除旧尝试。旧日志、栅栏令牌和回执共同解释为何接管。对于不安全活动,人工确认也应追加结构化事件,写明证据和操作者,而不是直接改状态。这样之后的重放仍能得到相同结论。

五、验证:在每个阶段注入死亡

测试应在领取前后、远端调用前后、回执写入前后和完成提交前后杀死 worker。安全活动最终应完成一次;不可判定活动应稳定停在人工状态;旧栅栏提交必须被拒绝。还要模拟心跳线程存活而业务线程卡死,验证进度监控能报警。

崩溃分类解决“能否接管”,下一篇继续约束“可以重试多少次”。没有预算的安全重试仍会形成流量风暴,并把永久错误伪装成暂时故障。

参考来源

  • Martin Kleppmann:分布式锁的栅栏令牌
  • Kubernetes:Lease
  • Google SRE:处理过载

👍 觉得有用就点个赞 + 收藏,方便回头查阅;有疑问直接在评论区留言,我看到都会回。

🚀 本文属于《持久化执行前置课》系列,持续更新,关注不迷路。

📌 文章里的代码都能直接跑。想要可直接 clone 的完整工程 + 配套部署脚本 / 踩坑清单?评论一声或发邮件到cj2664@qq.com,我免费发你。
如果你正好在做类似系统、或有工程化难题想找人做,也欢迎邮件聊一句——我按实际情况评估,能落地的就接单或出方案。评论和邮件都能直接找到我,不用跳别的平台。

http://www.jsqmd.com/news/1311476/

相关文章:

  • AI FaultLab:给 Hybrid RAG 补上检索评测闭环
  • 基于Jetson Orin与ESP32的AI机器人开发:从硬件选型到视觉跟踪实战
  • 微客外链功能解析:抖音_快手私信跳转微信的实现原理与技术路径
  • 2026 年当下,天河可靠的膜结构汽车棚电动车棚选哪家优质厂家哪家可靠,别再瞎花钱装车棚了?这款实用型靠谱方案竟能省出半台车钱 - 鉴选官
  • MP4转MP3全平台实战指南:原理、工具与音质优化
  • 2026夏天选旅行社看这篇:西藏旅行社推荐与投诉率大比拼,我们对比了20家,这份避坑名单请收好| 附:旅行社电话 - 西藏康泰旅行社
  • 2026 年当下,巴林右旗有实力的不锈钢洗手池工厂哪家强,用了十年才发现,这玩意儿比瓷砖省心10倍,看完赶紧换-丰卓不锈钢厨具设备 - 企业信息推荐【官方】
  • 【MiniMax H3技术解析】2K原生双声道、全模态控制与开源路线
  • Java 版本演进
  • USB转串口线缆全解析:从芯片选型到驱动配置与实战应用
  • 解决UE4编译中UnrealBuildTool复制失败问题的系统性指南
  • Pandas DataFrame索引重塑:从混乱数据到高效查询的完整指南
  • 深入解析502 Bad Gateway:从网关原理到系统排查实战
  • 工程案例|深圳长微科技半导体有限公司 3500㎡半导体封测无尘车间净化工程项目
  • MQTT协议深度解析:从发布订阅到QoS,构建物联网通信基石
  • SAP MIRO屏幕增强与GUI状态自定义:提升发票校验效率的实战指南
  • 解决Word中MathPage.WLL文件未找到错误的完整指南
  • AI服务合规化:从实名验证到隐私保护的技术架构与应对策略
  • 深入解析setAnalysisMode:动态控制数据采集的策略模式与工程实践
  • 嵌入式显示实战:11.9英寸HDMI LCD选型、驱动与抗干扰设计全解析
  • 高职AI专业升级有哪些成功案例?以广州科技职业技术大学为例
  • 8通道Modbus RTU模拟量输出模块选型、配置与编程实战指南
  • 2026 年现阶段,山东诚信的美麟鸡柳棒品牌哪家好,谁能想到街边炸串里藏着能把深夜馋虫拿捏得死死的这玩意儿? - 企业推荐官【认证官方】
  • 2026年海南ODI备案服务商甄选参考:专业实力与本地化能力解析 - 优质品牌商家
  • 2026年7月重庆代理记账公司哪家靠谱?正规财税机构头部知名榜 - 行业深度分析
  • USG防火墙强制主备切换命令
  • 计算机组成原理指令系统习题精解:从指令格式到程序执行全剖析
  • 忘记Redis是否安装过时查看
  • OB复盘分析:7/1/7辛德拉为何输掉比赛?从个人操作到团队决策的破局思考
  • 学嵌入式和C语言编程|学习日记Day11:各类数组作函数参数、变量作用域、生命周期、存储类别