长任务还活着吗:用进展租约区分卡住与依赖变慢
一个任务每秒上报心跳,十分钟没完成任何步骤。另一个任务正在等待供应商生成视频,三分钟没有新输出,却仍在预期时长内。只凭“几秒没动静就重启”,会把这两种情况混在一起。
活着、前进、拥有写权限
我会分别记三件事:heartbeat_at说明进程仍能通信;progress_at说明业务检查点确实前进;generation决定谁有权提交结果。心跳不能续期业务进展,日志刷屏也不能算完成步骤。
Kubernetes 探针文档区分启动、存活和就绪。它们是进程管理背景,不是业务任务完成度协议。任务层还需给各步骤定义正常等待区间,例如“视频供应商处理中”和“结果已下载”是不同检查点。
接管必须让旧 owner 失去提交资格
下面用逻辑时间演示 fencing。它不是分布式租约实现:真实系统要让数据库以条件更新原子地分配代次,并在每次落库时验证代次。
class Task: def __init__(self): self.owner, self.gen, self.progress = 'A', 1, 10 self.step = 0 def take(self, new_owner, now, timeout): if now - self.progress <= timeout: return None self.owner, self.gen = new_owner, self.gen + 1 self.progress = now return self.gen def commit(self, owner, gen, step, now): if (owner, gen) != (self.owner, self.gen) or step <= self.step: return False self.step, self.progress = step, now return True t = Task() assert t.take('B', 15, 10) is None assert t.take('B', 30, 10) == 2 assert not t.commit('A', 1, 1, 31) assert t.commit('B', 2, 1, 32) print('early takeover denied; stale owner fenced; new owner committed')本地 Python 3 执行通过三项断言,没有连接任务系统。这个实验把关键反例说清楚:超时后旧进程可能恢复,如果存储层不验代次,它依然能覆盖新结果。应用里单独检查一次再写入,会留下竞争窗口。
慢依赖别用重启“治疗”
每个检查点保存预期工作、最后进展证据和等待对象。超出观察窗口先检查供应商任务状态和本地积压;确认需要接管后,再撤销旧代次、分配新 owner。外部扣款、视频生成等副作用还要有稳定幂等键,否则 fencing 只能保护本地写,挡不住重复消费。
十月的视频 Agent 热点适合用这个框架审视,但本文不虚构某个平台耗时或重启收益。发布前应补齐真实依赖的等待上限、取消能力及幂等合同;未核实前,“卡住”只是待验证假设。