工作进程错误:工作进程过早退出,信号为15(SIGTERM)。

7

我最近在一个新的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已发送。 任务ID:b6ce2b97-d5b8-4850-9e43-9185426cd9f6
然而,在查看redis中的任务时,任务b6ce2b97-d5b8-4850-9e43-9185426cd9f6不存在。
因此,似乎任务并没有消失,而是根本没有被发送或被放入unacked的redis键中。

你是否遇到了与“正常”任务不是ETA或倒计时有相同的问题?工作进程突然停止,但还有足够的内存可用。你找出了原因吗? - kev
我放弃了使用Celery,但我认为问题与将数据库用作伪消息队列有关。一旦我转向Redis或RabbitMQ,我认为这个问题就解决了。 - Scott Coates
你现在只是使用普通的redis/rabbitmq吗?但你仍然在使用Python吗? - kev
4个回答

4
这些WorkerLostErrors的原因很可能是Celery和Heroku之间行为不兼容所致:
- Celery工作进程期望在父工作进程上收到SIGTERM信号,此时会让其子进程完成当前任务。 - 当对dyno进行“温暖关闭”时,Heroku向dyno中的所有进程发送SIGTERM信号。
因此,所有worker子进程也会收到SIGTERM信号,并立即开始终止,导致WorkerLostErrors。
为未发布的Celery 4.0准备了一个解决方法:https://github.com/celery/celery/issues/2839 我还没有找到3.1.19的解决方案。

1

WorkerLostError并不正常,你应该关注它。

至于长时间运行任务的确认/重启: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 ... 

0
今天我遇到了同样的问题。我的任务会生成子进程,但执行过程中会随机中断。

WorkerLostError('Worker exited prematurely: signal 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()

一切都变得正常。


我猜你的意思是相反的顺序:先执行pool.close(),然后再执行pool.join() - Zoltan Fedor

0

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

我认为希望在 SIGTERM 上不丢失任务远非偏执狂。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接