参考:https://mp.weixin.qq.com/s/FF1dzq3ItvZt36PgOqX_BQ
1 Celery 实现异步调用的原理核心其实是将任务执行单元 worker 和 任务派发单元 分开,从而达到异步的效果;
2Celery将需要执行的任务发送到消息队列中,然后再由任务执行单元根据具体的配置(绑定到具体哪个队列,默认为defaults)从消息队列中获取任务执行,这样就实现了异步的效果。
3 celery官方说明:http://docs.celeryproject.org/en/master/index.html
4
如果 使用下面这样类似绝对路径引用 函数的
from celery_app.task1 import add
可以在celery 中直接别识别。
add.apply_async(args=[2, 8],)
如果使用
from celery_app import task1
task1.add.apply_async(args=[2, 8],)
需要在Celery的配置文件导入的任务模块
CELERY_IMPORTS = ( # 指定导入的任务模块
'celery_app.task1',
'celery_app.task2'
)
否则会报错接收了未注册的任务 tasks.add
5 Celery 中要求每个task 具有不同的名称以便worker获取到消息之后能够准确的识别并且被处理。
6
对于 Celery 其内建任务状态有如下几种:
参数 说明
PENDING 任务等待中
STARTED 任务已开始
SUCCESS 任务执行成功
FAILURE 任务执行失败
RETRY 任务将被重试
REVOKED 任务取消
7
task.apply_async(args=[arg1, arg2], kwargs={key:value, key:value})
支持的参数 :
countdown : 任务延迟执行的秒数,默认立即执行
add.apply_async((32,29), countdown=5) # 等待5秒之后执行
eta : 任务被执行的绝对时间.
add.apply_async((32,29), eta=now+tiedelta(second=20)) #调用任务之后20秒之后开始执行
expires : 设置超时时间.
add.apply_async((32,29), expires=60)
retry : 定时如果任务失败后, 是否重试.
add.apply_async((32,29), retry=False)
retry_policy : 重试策略.
max_retries : 最大重试次数, 默认为 3 次.
interval_start : 重试等待的时间间隔秒数, 默认为 0 , 表示直接重试不等待.
interval_step : 每次重试让重试间隔增加的秒数, 可以是数字或浮点数, 默认为 0.2
interval_max : 重试间隔最大的秒数, 即 通过 interval_step 增大到多少秒之后, 就不在增加了, 可以是数字或者浮点数, 默认为 0.2 .
8
Celery 提供类似linux crontab的定时任务功能,需要在配置文件中引入CELERYBEAT_SCHEDULE,Celery的计划任务schedule 可以通过datetime.timedelta 或者 crontab两种方式实现
9
定时任务中如果使用 datetime.timedelta 则需要在配置中加入时区信息,否则默认是以 utc 为准。国内的使用者推荐加上
CELERY_TIMEZONE = 'Asia/Shanghai' # celery使用的时区
10 CELERYBEAT_SCHEDULE 中task 必须是任务的绝对路径,如
from celery.schedules import crontab from datetime import timedelta CELERYBEAT_SCHEDULE = { 'add-every-30-seconds': { 'task': 'celery_app.task1.add', 'schedule': timedelta(seconds=30), # 每 30 秒执行一次 'args': (5, 8), # 任务函数参数 }, 'sendmail-at-every-20-sec':{ 'task':'celery_app.task1.sendmail', 'schedule':timedelta(seconds=30), 'args': ('yangyi',), }, 'multiply-at-some-time': { 'task': 'celery_app.task1.multiply', 'schedule': crontab(hour=9, minute=50), # 每天早上 9 点 50 分执行一次 'args': (3, 7), # 任务函数参数 } }
11还有一种方式是 使用 celery 提供的periodic_task 作为装饰器,不过使用 periodic_task 不能和 CELERYBEAT_SCHEDULE同时使用
from celery_app import app
from celery.task import periodic_task
from celery.utils.log import get_logger
from celery.schedules import crontab
logger = get_logger(__name__)
@periodic_task(run_every=(crontab(minute='*/1')), name="add_func", args='yangyi', ignore_result=True) def sendmail(msg): logger.info('start send email to %s' %msg) return 'start send email to %s' %msg
12 使用队列
celery -A celery_app worker -l info -Q task_add,task_mail,task_mul,celery
In [1]: from celery_app.task1 import add,sendmail In [2]: sendmail.apply_async(('yangyi',), routing_key='mail')
13 celery状态:更全的状态列表详见官网:http://docs.celeryproject.org/en/master/_modules/celery/states.html
PENDING:任务等待中, STARTED:任务已开始, SUCCESS:任务执行成功, FAILURE:任务执行失败, RETRY: 任务将被重新执行, REVOKED:任务取消, PROCESS:任务执行中
READY_STATES = frozenset({SUCCESS, FAILURE, REVOKED})
UNREADY_STATES = frozenset({PENDING, RECEIVED, STARTED, REJECTED, RETRY})
14
14