后台消费者在容器终止时可能正处理队列消息、批处理分片或定时任务。立即退出会让消息重新投递;若任务已产生外部副作用却尚未确认,重试可能重复扣款、发通知或创建记录。优雅停机要建立清晰顺序:停止领取新工作、处理或安全释放在途任务、完成必要状态提交,最后才退出进程。⏳
应用收到SIGTERM后应切换到draining状态,拒绝新任务或停止向队列拉取消息。对已经领取的任务,按照业务约定完成、保存检查点,或安全释放租约以便稍后重试。不要立即关闭数据库和队列连接,因为当前任务可能仍需提交结果或确认消息。
排空期间要保持必要的心跳和租约续期。若队列租约在任务完成前到期,另一消费者可能开始处理同一任务,形成并发重复。停机宽限期也要覆盖任务处理、确认消息和客户端关闭的耗时;平台在宽限期结束后可能强制终止进程。🔔
许多消息系统提供至少一次投递:在消费端确认前,消息可能重投。若先确认后写入业务结果,进程崩溃可能造成任务丢失;若先写结果后确认,崩溃窗口可能导致重复执行。两步操作通常不共享一个事务,因此消费者需要设计幂等保护。
可使用稳定任务ID建立处理记录、数据库唯一约束或业务状态机,确保同一任务重复到达时不会重复产生副作用。对于外部支付、邮件或第三方调用,应使用对方支持的幂等键,或记录请求结果并对重试进行协调。幂等记录的保存时间要覆盖可能的重投窗口,不能任务刚完成就立即删除。📦
先测量任务耗时分布,区分短任务、长尾任务和无界任务。设置任务超时、队列可见性期限或租约续期策略时,确保正常长尾任务不会在仍被处理时被其他消费者重新领取。若任务可能超过容器终止宽限期,应支持检查点、分片续作或安全中断,而不是指望无限延长停机时间。
还要确认编排平台是否在终止前先从服务端点摘除实例、信号如何传递、进程是否由正确的入口进程接收SIGTERM,以及子进程是否一同退出。只读代码和配置检查之外,可在隔离环境使用docker stop观察信号处理和最终退出码。⏱️
监控在途任务数、待处理队列深度、任务耗时分位数、租约续期失败、确认延迟、重投次数、幂等命中次数和停机耗时。若退出期间在途数不下降,可能是任务卡住或停机逻辑仍在领取新任务;若重投在租约到期点激增,应检查任务耗时与租约时长关系。
日志应包含任务ID、处理阶段和结果,不记录敏感载荷。使用同一任务ID关联首次处理、停机和重投事件,可以判断是任务真的重复执行,还是日志重复采集。停机期间应用仍应输出可诊断状态,但日志写入失败不能阻塞关键清理流程。📊
容易误判:优雅停机能缩小重复执行窗口,却无法消除所有崩溃时序。队列重投是正常机制,可靠性仍依赖幂等处理和可验证的业务状态。🛡️