如何使用Celery,RabbitMQ和Django确保每个用户的任务执行顺序?

时间:2015-04-30 12:31:45

标签: python django rabbitmq celery django-celery

我正在运行Django,Celery和RabbitMQ。我想要实现的是确保与一个用户相关的任务按顺序执行(具体来说,当时一个,我不希望每个用户的任务并发)

  • 每当为用户添加新任务时,它应该取决于最近添加的任务。其他功能可能包括不将任务添加到队列,如果此类型的任务已为此用户排队且尚未启动。

我做了一些研究并且:

  • 我无法找到一种方法将新创建的任务与已在Celery中排队的任务相关联,链条似乎只能链接新任务。
  • 我认为使用自定义RabbitMQ消息处理程序可以实现这两种功能,但毕竟可能很难编码。
  • 我也读过关于celery-tasktree的内容,这可能是确保执行顺序的最简单方法,但是如何将新任务与已经“applied_async”task_tree或队列相关联?有什么方法可以使用这个包实现额外的无重复功能吗?

编辑:celery cookbook中还有这个“锁定”示例,因为概念很好,我看不出一种可能的方法让它在我的情况下按预期工作 - 只要我能'为用户获取锁定,必须重试任务,但这意味着将其推送到队列末尾。

这里最好的做法是什么?

1 个答案:

答案 0 :(得分:0)

如果您配置芹菜工作者,以便他们一次只能执行一个任务(请参阅worker_concurrency设置),那么您可以基于每个用户强制执行所需的并发。使用像

这样的方法
 NUMBER_OF_CELERY_WORKERS = 10

def get_task_queue_for_user(user):
    return "user_queue_{}".format(user.id % NUMBER_OF_CELERY_WORKERS)

根据用户ID获取任务队列,每个任务将被分配给每个用户的同一队列。需要将工作程序配置为仅从单个任务队列中使用任务。

它会像这样发挥:

  1. 用户49触发任务

  2. 任务将发送至user_queue_9

  3. 当正在监听user_queue_9的唯一芹菜工作者准备好消耗新任务时,任务就会执行

  4. 这是一个hacky的答案,因为

    • 每个队列只需要一个芹菜工人是一个脆弱的系统 - 如果芹菜工人停止,整个队列停止

    • 工人效率低下