【问题标题】:How to duplicate Django Celery worker?如何复制 Django Celery 工人?
【发布时间】:2012-07-02 11:11:57
【问题描述】:

我在 Celery 中有一个记录器(使用 RabbitMQ),并希望在紧急情况下复制它的工作。

# tasks.py
@task
def log(message):
    with open('test.txt', 'a') as f:
        f.write(message)


# views.py
log.delay(message)

如何让不同机器上的 2 个 Celery 实例在调用时运行 log()

这样做有意义吗?

这在 RabbitMQ 中是可能的。如果您有topic-based exchange,则很明显可以将一条消息放入两个不同的队列并独立地传递给 2 个接收者。

sender =>
[message, routing_key=event.logging.log] => [queue A, topic=event.#]     
                                                      => receiver 1
                                         => [queue B, topic=*.logging.*]
                                                      => receiver 2

消息将被发送到两个队列,它们都不会从另一个队列中窃取消息。

【问题讨论】:

    标签: django rabbitmq celery


    【解决方案1】:

    为此,您必须将交换配置为主题交换(如您所说):

    CELERY_QUEUES = {
       'celery': {
           'exchange': 'celerytopic',
           'exchange_type': 'topic',
           'routing_key': 'celery',
       },
    }
    

    然后您可以使用 AMQP api 创建备份交换:

     from celery import current_app as celery
    
     with celery.broker_connection() as conn:
         conn.default_channel.queue_declare(queue='celery.backup', durable=True)
         conn.default_channel.queue_bind(queue='celery.backup',
                                         exchange='celerytopic',
                                         routing_key='celery',
                                         durable=True)
    

    由于您已经有一个名为 celery 的队列,您可能需要先将其删除:

    $ camqadm queue.delete celery
    

    【讨论】:

      【解决方案2】:

      尝试在两台不同的机器上启动此任务对我来说没有意义。至少 Celery 不能保证一个任务会在不同的机器上运行——它是 RabbitMQ 分配负载,如果一个节点的负载比其他节点少——运行的两个任务可能会在那台机器上执行......

      请改用task.retry。如果执行失败,Celery 将重试任务。 Celery 足够聪明,可以理解任务是否失败。只需确保在任务失败时引发一些异常,如果无法成功记录则不要静默返回。

      更新:

      一个可能的工作流程可能是 - 尝试执行任务,如果失败,在 on_retry 中更改 routing_key,并尝试在可能是您的故障转移队列的不同交换/队列中执行任务。

      【讨论】:

      • 我会在 RabbitMQ 上添加评论。
      • 我的观点是,如果在同等配置的节点之间进行简单的负载平衡,您无法选择哪个节点将执行任务。至少这是通常的故障转移行为。如果您将任务限制为在某些节点上运行 - 那么您将自动失去故障转移,并且您将被绑定到选定的节点。如果他们都死了..你仍然有运行的节点,但不会使用它们。或者简单地说 - 如果它会失败 - 你将很难在启动 2 个同时任务时获得灵活性。你会采用更安全的方法 - 即使用 on_retry() 函数来处理重试。
      • 对答案的一个小更新。此外 - 使用正确的返回值,您可以引发实际异常并将其发送到另一个队列。想象一下,您的机器上的磁盘空间不足,无论如何都不会重试。但是,在紧急情况下,发送带有实际错误(即“磁盘已满”)的电子邮件的故障转移更有意义。
      猜你喜欢
      • 2014-08-20
      • 2021-09-08
      • 2022-01-12
      • 2021-12-12
      • 2016-07-15
      • 2021-08-18
      • 2019-05-28
      • 2014-12-06
      • 2015-06-23
      相关资源
      最近更新 更多