Python 芹菜停工工人完成特定任务后

Python 芹菜停工工人完成特定任务后,python,celery,Python,Celery,我正在使用芹菜(solo pool with concurrency=1),我希望能够在特定任务运行后关闭辅助进程。需要注意的是,我希望避免工人在这之后再接任何其他任务的可能性 以下是我在大纲中的尝试: from __future__ import absolute_import, unicode_literals from celery import Celery from celery.exceptions import WorkerShutdown from celery.signals

我正在使用芹菜(solo pool with concurrency=1),我希望能够在特定任务运行后关闭辅助进程。需要注意的是,我希望避免工人在这之后再接任何其他任务的可能性

以下是我在大纲中的尝试:

from __future__ import absolute_import, unicode_literals
from celery import Celery
from celery.exceptions import WorkerShutdown
from celery.signals import task_postrun

app = Celery()
app.config_from_object('celeryconfig')

@app.task
def add(x, y):
    return x + y

@task_postrun.connect(sender=add)
def shutdown(*args, **kwargs):
    raise WorkerShutdown()
然而,当我运行工人时

celery -A celeryapp  worker --concurrency=1 --pool=solo
然后运行任务

add.delay(1,4)
我得到以下信息:

 -------------- celery@sam-APOLLO-2000 v4.0.2 (latentcall)
---- **** ----- 
--- * ***  * -- Linux-4.4.0-116-generic-x86_64-with-Ubuntu-16.04-xenial 2018-03-18 14:08:37
-- * - **** --- 
- ** ---------- [config]
- ** ---------- .> app:         __main__:0x7f596896ce90
- ** ---------- .> transport:   redis://localhost:6379/0
- ** ---------- .> results:     redis://localhost/
- *** --- * --- .> concurrency: 4 (solo)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[2018-03-18 14:08:39,892: WARNING/MainProcess] Restoring 1 unacknowledged message(s)
任务将重新排队,并将在另一个辅助进程上再次运行,从而导致循环

当我在任务本身中移动
WorkerShutdown
异常时,也会发生这种情况

@app.task
def add(x, y):
    print(x + y)
    raise WorkerShutdown()

有没有一种方法可以在完成特定任务后关闭工人,同时避免这种不幸的副作用?

建议关闭工人的过程是发送
术语
信号。这将导致芹菜工人在完成任何当前正在运行的任务后关闭。如果向工作进程的主进程发送退出信号,工作进程将立即关闭

然而,芹菜文档通常从命令行或通过systemd/initd管理芹菜的角度来讨论这一点,但是芹菜还通过
芹菜.app.control
提供了远程工作者控制API 您可以创建一个任务来阻止工作人员执行该任务。这将防止您遇到的循环。此外,控制也以这种方式支持工人的工作

所以我想下面的内容会让你得到你想要的行为

@app.task(bind=True)
def shutdown(self):
    app.control.revoke(self.id) # prevent this task from being executed again
    app.control.shutdown() # send shutdown signal to all workers
由于当前无法从任务内确认任务,然后继续执行所述任务,因此使用
撤销
的这种方法可以避免此问题,因此,即使任务再次排队,新工作人员也会忽略它

或者,以下操作也会阻止重新交付的任务再次执行

@app.task(bind=True)
def some_task(self):
    if self.request.delivery_info['redelivered']:
        raise Ignore() # ignore if this task was redelivered
    print('This should only execute on first receipt of task')

同样值得注意的是,还有一个
revoke
方法,可以为您调用
self.app.control.revoke

如果您关闭工作进程,在任务完成后,它将不会再次排队

@task_postrun.connect(sender=add)
def shutdown(*args, **kwargs):
    app.control.broadcast('shutdown')
这将在任务完成后正常关闭工作进程

[2018-04-01 18:44:14,627: INFO/MainProcess] Connected to redis://localhost:6379/0
[2018-04-01 18:44:14,656: INFO/MainProcess] mingle: searching for neighbors
[2018-04-01 18:44:15,719: INFO/MainProcess] mingle: all alone
[2018-04-01 18:44:15,742: INFO/MainProcess] celery@foo ready.
[2018-04-01 18:46:28,572: INFO/MainProcess] Received task: celery_worker_stop.add[ac8a65ff-5aad-41a6-a2d6-a659d021fb9b]
[2018-04-01 18:46:28,585: INFO/ForkPoolWorker-4] Task celery_worker_stop.add[ac8a65ff-5aad-41a6-a2d6-a659d021fb9b] succeeded in 0.005628278013318777s: 3   
[2018-04-01 18:46:28,665: WARNING/MainProcess] Got shutdown from remote
注意:广播将关闭所有工作人员。如果要关闭特定的辅助进程,请使用名称启动辅助进程

celery -A celeryapp  worker -n self_killing --concurrency=1 --pool=solo
现在,您可以使用目标参数关闭它

app.control.broadcast('shutdown', destination=['celery@self_killing'])

如果您需要关闭特定工作进程,并且事先不知道它的名称,则可以从任务属性中获取它。根据以上答案,您可以使用:

app.control.shutdown(destination=[self.request.hostname])

注意:

  • 工作人员应以名称开头(选项
    '-n'
  • 任务应使用
    bind=True
    参数定义

尝试使用
os.kill(os.getpid(),signal.SIGTERM)
看看是否有帮助。尝试这两种方法您已经尝试过了如果worker是
芹菜
进程的子进程,那么您应该尝试
操作系统。getppid()
这里的想法是,worker在单个任务运行后永远不会重新启动吗?是的,这就是想法。@samfrances,您没有提供任何反馈或评论。请更新
app.control.broadcast('shutdown', destination=[self.request.hostname])