给任务配了 soft_time_limit 三百秒,实际跑了二十多分钟才结束,日志里没有 SoftTimeLimitExceeded,超时配置像没生效,重启 worker 也一样,换台机器也一样。日志里能对上时间点,这种反而好排。
软超时靠信号实现,只在支持信号的主进程或 prefork 子进程里生效,任务里再用线程池或者协程运行时收不到信号,限制自然不起作用。这一点先确认清楚,后面就不用反复试。
@app.task(soft_time_limit=300, time_limit=360)
def reconcile():
try: run()
except SoftTimeLimitExceeded: cleanup()
这次卡住的地方就在「Celery 软超时失效」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。
别只看报错的最后一行,往上看几行,真正的起因通常在上面。
处理上按这个顺序:确认 worker 池类型是 prefork,别用线程池去跑带超时的任务,信号送不到;软超时异常要在任务内部捕获,捕获后把中间状态清理掉;硬超时同时配上,防止软超时被忽略,进程被硬杀也有记录。
结果对不对很好判断,超时任务在五分钟左右被中断,日志里能看到 SoftTimeLimitExceeded,清理逻辑也跑了。
