一个跑十二分钟的对账任务,日志里同一单号出现两次执行记录,第二次在开始后第十分钟插入,两条都往结果表写了数据。乍看像缓存或者权限的锅,追下去往往不是。

app.conf.broker_transport_options = {
    'visibility_timeout': 3600,
}
app.conf.task_acks_late = True

追下去是这么回事:Redis 作为 broker 时消息有可见性超时,项目里把默认值改成了十分钟,任务还没确认前又被重新投递,另一个 worker 取走再跑一遍,同一单号落两次库。

「Celery 任务重复」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。接口问题先分清是没发出去、发出去了没收到,还是收到了处理失败。

偶发问题先统计频率,一小时几次和一天一次,查法完全不同。

具体做法是,把 visibility_timeout 调到比最长任务耗时再多两分钟,留出确认时间;任务加上幂等键,重复执行前先查一次状态,已完成的直接返回;长任务拆成几段,减少单次占用时间,也少占预取额度。

验收就看一点,同一单号只出现一条执行记录,结果表没有重复行,幂等键生效。

作者 9823189