这个坑值得记一笔。推理服务先把幂等记录写成 processing 再执行任务,跑完改成 succeeded。一次进程被 kill 之后记录停在 processing,上游重试时服务看到状态就直接返回 409,任务再也起不来,最后只能人工改库放行。

刚开始盯着「返回 409 后上游按不可重试处理,链路直接断掉」,折腾了半个多小时,排掉了。

把日志和配置对完,能解释这个现象的基本就这几处。状态机没有超时回收,processing 会永久停留;执行与状态更新之间没有事务或补偿逻辑;记录里没存开始时间,判不出是执行中还是卡死。

先查出卡住超过十分钟的记录

psql -c "SELECT id,status,started_at FROM idem WHERE status='processing' AND started_at < now() - interval '10 min';"

接着把超时记录回收成可重试状态

psql -c "UPDATE idem SET status='pending',started_at=null WHERE status='processing' AND started_at < now() - interval '10 min';"

补一个定时回收任务并限制最长执行时间

python reap_idem.py --max-age 600 --dry-run

等前面都确认过,再重放该请求确认能正常走完

curl -s -X POST http://api:8080/jobs -H 'Idempotency-Key: job-8842' -d @job.json | jq '.status'

怎么算真的好了,看的是同一批现象。卡住的记录回收后重放返回 200,状态从 pending 走到 succeeded,十分钟内没有新的 processing 残留。

幂等状态机必须自带超时回收,一次进程退出就会把对应请求永久锁死,人工改库只是临时办法。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189