WorkerLostError('工人过早退出:信号15(SIGTERM)。')

时间:2014-01-15 00:31:50

标签: python redis celery

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

 -------------- 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密钥。

4 个答案:

答案 0 :(得分:4)

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

  • Celery工作者期望在父工作进程上使用SIGTERM,在这种情况下,它允许其子进程完成当前任务。
  • 进行热关机时#39对于dyno,Heroku将一个SIGTERM发送到dyno中的所有进程。

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

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

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

答案 1 :(得分:0)

WorkerLostError不正常,你绝对应该担心。

对于长时间工作的ack / restarts:Celery尽力而为,但如果你是偏执狂,即使父母/工人在特殊情况下死亡,你也期望有保证的交付/执行/确认模式,你可能会考虑使用辅助数据存储来跟踪进度和元数据,以便您可以进行细粒度控制:

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 :(得分:0)

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

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

答案 3 :(得分:0)

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

  

WorkerLostError('工人过早退出:信号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发送给生成的进程,而且也发送给自己。 当我将pool.terminate()更改为:

pool.join()
pool.close()
一切都变好了。