【问题标题】:WorkerLostError('Worker exited prematurely: signal 15 (SIGTERM).',)WorkerLostError('Worker 提前退出:信号 15 (SIGTERM).',)
【发布时间】:2014-02-03 07:17:23
【问题描述】:

我最近开始在一个新的 Django 项目中使用 celery。设置:

 -------------- celery@123 v3.1.7 (Cipater) 
---- **** -----  
--- * ***  * -- Linux-3.8.11-ec2-x86_64-with-debian-squeeze-sid 
-- * - **** ---  
- ** ---------- [config] 
- ** ---------- .> app:         nextlanding_api:0x1c23250 
- ** ---------- .> transport:   redis://rediscloud@123123 
- ** ---------- .> results:     djcelery.backends.database:DatabaseBackend 
- *** --- * --- .> concurrency: 4 (prefork) 
-- ******* ----  
--- ***** ----- [queues] 
 -------------- .> celery           exchange=celery(direct) key=celery 

software -> celery:3.1.7 (Cipater) kombu:3.0.8 py:2.7.4
            billiard:3.3.0.13 redis:2.9.0
platform -> system:Linux arch:64bit, ELF imp:CPython
loader   -> celery.loaders.app.AppLoader
settings -> transport:redis results:djcelery.backends.database:DatabaseBackend 

我正在调查一个问题,即 eta 超过 24 小时的任务消失(我已确保 visibility_timeout 超过 24 小时)。当我热情地关闭工作人员时,日志语句显示了几条正在确认的消息。例子: Restoring 26 unacknowledged message(s).

但是,我预计会恢复大约 50 条左右未确认的消息。仔细查看我的日志,我看到:

[ERROR] celery.worker.job: Task myproj_task[xxx] raised unexpected: WorkerLostError('Worker exited prematurely: signal 15 (SIGTERM).',)
...
WorkerLostError: Worker exited prematurely: signal 15 (SIGTERM). 
Restoring 26 unacknowledged message(s). 
Process exited with status 0 

我看到其他人报告 OOM 杀死了他们的进程。我在 Heroku 上,没有看到 R14 代码。

最后一点,我正在从我的任务中生成新进程。

我的问题是:WorkerLostError 是我应该担心的吗?状态码是 15 (SIGTERM),这似乎没问题。如果此错误不正常,是否可能导致丢失 ETA 任务?

编辑

起初我以为项目消失了,但在放入一些详细日志后,我可以看到任务已发出但从未保留在 redis 中:

myproj_email_task was sent. task_id: b6ce2b97-d5b8-4850-9e43-9185426cd9f6

但是,查看redis中的任务,任务b6ce2b97-d5b8-4850-9e43-9185426cd9f6并不存在。

所以看起来任务并没有消失,而是根本没有发送或没有被放入unacked redis 键中。

【问题讨论】:

  • “正常”任务也有同样的问题,不是 eta 或倒计时。工人刚刚死去,还剩下很多内存。你找到它的原因了吗?
  • 我离开了 celery,但我认为这个问题与将数据库用作虚假消息队列有关。一旦我转移到 redis 或 rabbitmq,我认为这个问题会自行解决。
  • 你现在只是在使用普通的 redis/rabbitmq 吗?但是你还在用 Python 吗?

标签: python redis celery


【解决方案1】:

WorkerLostError 是不正常的,你一定要担心。

关于长时间运行的作业的 ack/restarts:Celery 已尽其所能,但如果您偏执,并且即使在父/工人在异常情况下死亡时也期望有保证的交付/执行/ack 模型,您可能会考虑使用辅助数据存储来跟踪进度和元数据,以便您进行细粒度控制:

Client->TransactionalDB: insert JOB
Client->Celery: send_async(job_id)
Celery->Worker: do(job_id)
Worker->TransactionalDB: update started job + meta
...
Worker->TransactionalDB: update progress + meta
...
?->Worker: die!
...
Celerybeat->Worker: checkForOrphans()
Worker->TransactionalDB: select where ... 

【讨论】:

    【解决方案2】:

    WorkerLost on SIGTERM 绝对不正常。在这种情况下,如何在不丢失任务的情况下重新启动进程?即使ack_late 选项也无济于事。

    我认为不要在SIGTERM 上丢失任务的愿望远非偏执。

    【讨论】:

      【解决方案3】:

      这些 WorkerLostErrors 的原因很可能是 Celery 和 Heroku 的行为不兼容:

      • Celery 工作进程希望父工作进程有一个 SIGTERM,在这种情况下,它会让其子进程完成当前任务。
      • 当对测功机进行“热关机”时,Heroku 会向测功机中的所有进程发送 SIGTERM。

      因此,所有工作子进程也获得 SIGTERM 并立即开始终止,从而导致 WorkerLostErrors。

      已为未发布的 Celery 4.0 准备了解决方法:https://github.com/celery/celery/issues/2839

      我还没有找到 3.1.19 的解决方案。

      【讨论】:

        【解决方案4】:

        我今天遇到了同样的问题。我有一个生成子进程的任务,并且执行被随机中断

        WorkerLostError('Worker 提前退出:信号 15 (SIGTERM).

        最后我发现它的原因在这里: 我使用 multiprocessing.Pool 来生成新进程:

        from multiprocessing import Pool as ThreadPool
        pool = ThreadPool(2)
        data = pool.map( some_func, some_data) 
        pool.terminate()
        

        似乎 pool.terminate() 有时不仅会向衍生进程发送 SIGTERM,还会向其自身发送 SIGTERM。 当我将 pool.terminate() 更改为:

        pool.join()
        pool.close()
        

        一切都变好了。

        【讨论】:

        • 我猜你的意思是相反的顺序:首先是pool.close(),然后是pool.join()
        猜你喜欢
        • 2017-11-21
        • 2016-03-17
        • 1970-01-01
        • 2018-11-02
        • 2014-05-13
        • 2016-07-18
        • 1970-01-01
        • 1970-01-01
        • 2016-01-20
        相关资源
        最近更新 更多