【问题标题】:Celery execute tasks in the order they get called (during runtime)Celery 按照调用顺序执行任务(在运行时)
【发布时间】:2020-02-19 06:13:23
【问题描述】:

我有一个由链中的子任务组成的任务。如何确保在第一个任务完成之前不会开始第二次调用此任务?

@shared_task
def task(user):
    res = chain(subtask_1.s(), # each subtask takes ~1 hour
            subtask_2.s(),
            subtask_3.s())

    return res.apply_async()

django 视图现在可能会触发调用此任务:

# user A visits page that triggers task
task.delay(userA)
# 10 seconds later, while task() is still executing, user B visits page
task.delay(userB) 

这会导致任务相互竞争,而不是按顺序执行。例如。一旦工作人员完成了第一个任务的subtask_1(),它就会开始处理第二个任务的subtask_1(),而不是第一个任务的subtask_2()subtask_3()

有没有办法优雅地避免这种情况?我想问题是子任务添加到队列中的顺序。

  1. 我已经设置了worker --concurreny=1,但是这仍然不会改变他从队列中消费的顺序。
  2. Official docs (task cookbook) 似乎提供了一个我不理解的解决方案,不幸的是对我不起作用。
  3. 也许在任务链之后包含一个阻塞机制,带有while not res.ready(): sleep(1) 类型的hack?

【问题讨论】:

    标签: python django celery django-celery


    【解决方案1】:

    您可以等待第一个任务完成,然后像这样执行第二个任务。

    res = task.delay(userA)
    res.get() # will block until finished
    task.delay(userB)
    

    但它会阻塞调用线程,直到第一个线程完成。您可以链接任务以避免阻塞,但为此您必须稍微修改任务签名以接受任务结果作为参数。

    @shared_task
    def task(_, user): signature takes one extra argument
        # skipped
    

    from celery.canvas import chain
    
    
    chain(task.s(None, userA), task.s(userB))()
    

    【讨论】:

    • 是的,理想情况下,我希望您的链中描述的行为。但是,有没有办法在运行时动态创建、执行甚至修改这样的链?由于我不知道何时会调用第二个(或第三个,..)任务,是否可以将任务附加到已经执行的链中?感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-19
    • 1970-01-01
    • 2019-12-06
    • 2018-04-14
    • 1970-01-01
    • 1970-01-01
    • 2015-02-15
    相关资源
    最近更新 更多