redis 当代理丢失并重新连接时,防止Celery重新运行任务

pexxcrt2  于 2023-04-29  发布在  Redis
关注(0)|答案(1)|浏览(172)

我需要帮助解决生产环境中的问题。
我们的设置:

  • 由Cherrypy运行的flask应用程序
  • Celery处理后台任务
  • RabbitMQ作为消息代理(也尝试了redis)
  • MySQL for数据库

问题:
一旦Celery正在处理一个任务,并且它运行的时间上级了代理的心跳间隔,代理就关闭连接。一旦任务在Celery中完成处理并且代理停机,它只会重新启动任务。
任务不是幂等的,它们应该运行一次,即使失败也只能运行一次。我没有找到一种方法来防止这种行为,我已经尝试了celery 设置的所有组合。
下面是我的Celery配置:

CELERY = {'broker_url': 'amqp://**:******@127.0.0.1:5672/rdcovhost',
          'result_backend': 'rpc://**:******@127.0.0.1:5672/rdcovhost',
          'broker_pool_limit': 100, 'broker_connection_timeout': 6000,
          'worker_cancel_long_running_tasks_on_connection_loss': True, 'broker_heartbeat': 10,
          'broker_transport_options': {'visibility_timeout': 3600}, 'task_ignore_result': True, 
          'task_publish_retry': False, 'task_acks_late': False}

备注:

  • 当然,将心跳增加到一个非常高的值是解决方案的一部分,但不是真实的的解决方案,因为我们希望适应真正的代理间歇性连接
  • 将所讨论的任务修改为幂等也是一种解决方案,但可能需要大量时间才能实现,因此肯定有一个简单的解决Celery行为的方法
  • 如果Celery worker本身崩溃,则不重复该任务
  • 如果代理长时间处于关闭状态,则重新启动该任务
fnvucqvd

fnvucqvd1#

对于那些可能会遇到这个问题的人,我做了以下工作(不是一个最终的解决方案,但被认为是可以接受的生产):

  • 我在调试日志中注意到,重新排队时的任务有一个名为'redelivered'的额外标志,其值为'True'
  • 因此,在我运行的任务中,我评估了这个标志,如果为真,则引发异常以完全放弃任务,瞧!

执行此操作的代码:

if self.request.delivery_info.get('redelivered'):
        raise Reject('Task is being redelivered')

相关问题