通过send_task链接芹菜中的两个远程任务

时间:2015-07-06 06:44:53

标签: celery

在芹菜中,我想将远程工作者的两个任务链接在一起。有人可以告诉我如何在send_task中指定它吗?或者还有其他方法来调用远程任务吗?

BR

5 个答案:

答案 0 :(得分:3)

最简单的方法是使用'签名'功能:

from celery import signature
chain = signature(
  'app_name.task_1',
  kwargs={..},
  queue='this_queue'
)
chain |= signature(
  'app_name2.task2',
  kwargs={..},
  queue='another_queue'
)
chain.apply_async()

答案 1 :(得分:2)

我试图做同样的事情。我无法找到任何内置功能来完全按名称生成任务,但添加此类工具并不困难:

from celery import Task as BaseTask

class Task(BaseTask):
    def __init__(self, name, *args, **kwargs):
        super(BaseTask, self).__init__(*args, **kwargs)
        self.name = name

通过这门课程,您可以执行以下操作:

(
    Task('worker.hello').s('world') | 
    Task('messaging.email-results').s(email_address='user@company.com')
)()

或者,或者:

app.send_task(
    'worker.hello', ['world'], 
    chain=[
        Task('messaging.email-results').s(email_address='user@company.com')
    ]
)

修改

忽视上面,我已经意识到这样做的正确方法是使用Signature类(如下面的@Chrismit所述):

from celery import Signature

(
    Signature('worker.hello', args=['world']) | 
    Signature('messaging.email-results', kwargs={'email_address':'user@company.org'})
)()

或者,或者:

from celery import Signature

app.send_task(
    'worker.hello', ['world'], 
    chain=[
        Signature('messaging.email-results', kwargs={'email_address': 'user@company.com'})
    ]
)

一个重要的注意事项:链中的第一个任务之后的任何任务实际上都没有安排,直到一个工人在它之前处理任务(这是有道理的,因为我们不知道输入用于以后的任务,直到上一个任务运行)。 后续任务安排在工作人员的代码库中。因此,您需要确保满足以下条件之一:

  • 您的每个工作人员都了解task_routes,以便将后续任务放在适当的队列中(例如,在我的示例中,应该知道以messaging.*开头的任务应该在'messaging'队列)
  • 您在创建链时已将正确的queue编码到每个Signature类中。 Celery已经有了一个工具来从任务名称派生一个队列名称,该名称可以倾斜:

    def get_queue_name(task_name):
        return app.amqp.router.route({}, task_name)['queue'].name
    
    (
        Signature('worker.hello', args=['world']) | 
        Signature(
            'messaging.email-results',
            kwargs={'email_address':'user@company.org'},
            queue=get_queue_name('messaging.email-results')  # If typing the task name twice annoys you, you could subclass Signature to do this automatically
        )
    )()
    

    (我认为这是最干净的解决方案,因为它允许工人彼此不了解)

  • 所有任务都在默认队列中执行。如果您没有在工作人员上声明任何task_routes,并且任务的签名中没有指定queue,那么Celery将在工作人员中安排该任务default_queue。除非自定义,即'celery'。我强烈建议这样做,因为它不是非常明确,并且不允许进行大量队列管理,但仍然是一种选择。

答案 2 :(得分:0)

我是这样做的: 诀窍是你必须从你的任务名称中创建新的签名。

app.send_task("{0}.{1}".format(app_name,task),args, link = [app.signature("{0}.{1}".format(app_name,task),next_args)])

答案 3 :(得分:0)

出于某种原因,这种签名方法对我不起作用。它虽然成功创建了签名对象:

signature("some_remote_task", ...)

我的celery版本是4.4,“some_remote_task”定义如下:

    celery_app.conf.CELERY_ROUTES = {
        "some_remote_task": {
            "queue": "remote_queue",
            "routing_key": "key",
        }
    }

然后,由于某种原因,我意识到签名中的 _app=None。像这样通过后,它起作用了:

signature("some_remote_task", app=celery_app, ...)

答案 4 :(得分:-4)

你可以使用芹菜canvas objects

from celery import chain
my_chain = chain(task1.s((arg1, arg2)), task2.s((arg3, arg4))
result = my_chain.apply_async()