【celery】任务重复执行

问题

celery定时任务里面启用延时任务,出现延时任务重复执行的问题。
如:
定时任务:

'project_schedule_task': {
            'task': 'apps.project.tasks.project_status_monitor',
            'schedule': crontab(minute=0, hour=2),
        }

project_status_monitor任务执行时,再生成若干个延迟任务:

send_company_project_daily_remind_msg.apply_async(
                (company.name,
                 date_str,
                 company.push_title,
                 company.push_content,
                 None if company.push_weather_enable is False else city_weather_map,
                 project_list,
                 exec_time),
                countdown=company.push_time*60)

这时如果countdown配置的时间太长,该任务回重复执行多次。

问题原因及解决方法

Visibility timeout
If a task isn’t acknowledged within the Visibility Timeout the task will be redelivered to another worker and executed.

This causes problems with ETA/countdown/retry tasks where the time to execute exceeds the visibility timeout; in fact if that happens it will be executed again, and again in a loop.

So you have to increase the visibility timeout to match the time of the longest ETA you’re planning to use.

Note that Celery will redeliver messages at worker shutdown, so having a long visibility timeout will only delay the redelivery of ‘lost’ tasks in the event of a power failure or forcefully terminated workers.

Periodic tasks won’t be affected by the visibility timeout, as this is a concept separate from ETA/countdown.

You can increase this timeout by configuring a transport option with the same name:

app.conf.broker_transport_options = {'visibility_timeout': 43200}
The value must be an int describing the number of seconds.

原因是对于eta/countdown延迟任务,有超时时间,如果超过超时时间任务未被执行,会被丢到下一个worker去执行,造成循环执行。当我们设置一个ETA时间比visibility_timeout长的任务时,每过一次 visibility_timeout 时间,celery就会认为这个任务没被worker执行成功,重新分配给其它worker再执行

  • 解决方法
    重设超时等待时间:
app.conf.broker_transport_options = {'visibility_timeout': 86400}

排查过程中用到的一些命令记录

  • 查看celery eta任务队列
celery -A proj inspect scheduled
celery -A proj inspect scheduled |wc -l
  • 关闭任务
celery -A proj control terminate 
  • 关闭worker
pkill -9 -f 'celery worker'
ps auxww | awk '/celery worker/ {print $2}' | xargs kill -9
  • 重启worker
celery multi start 1 -A proj -l info -c4 --pidfile=/var/run/celery/%n.pid
celery multi restart 1 --pidfile=/var/run/celery/%n.pid

参考:https://docs.celeryproject.org/en/stable/userguide/workers.html

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。