任务调度delay&apply_async
delay与apply_async都是用来做任务调度,但如果查看delay的源码会发现最终还是调用了apply_async,简单来说delay就是apply_async的快捷方式,而apply_async则有很多参数来控制任务调度。
apply_async支持常用参数:
- eta:指定任务执行时间,类型为datetime时间类型;
- countdown:倒计时,单位秒,浮点类型;
- expires:任务过期时间,如果任务在超过过期时间还未执行则回收任务,浮点类型获取datetime类型;
- retry:任务执行失败时候是否尝试,布尔类型。;
- serializer:序列化方案,支持pickle、json、yaml、msgpack;
- priority:任务优先级,有0~9优先级可设置,int类型;
- retry_policy:任务重试机制,其中包含几个重试参数,类型是dict如下:
max_retries:最大重试次数
interval_start:重试等待时间
interval_step:每次重试叠加时长,假设第一重试等待1s,第二次等待1+n秒
interval_max:最大等待时间
Celery设置参数说明
- CELERY_DEFAULT_QUEUE 默认队列
- CELERY_RESULT_BACKEND 存储地址
- CELERY_TASK_SERIALIZER 任务序列化方式
- CELERY_RESULT_SERIALIZER 任务结果序列化方式
- CELERY_TASK_RESULT_EXPIRES 任务过期时间
- CELERYD_CONCURRENCY 任务并发数
- CELERYBEAT_SCHEDULE 任务调度
- CELERY_QUEUE 自定义任务队列
CELERY_QUEUE = (
Queue('default',exchange=Exchange('default'), routing_key="default.#"), # 路由键 以 "default." 开头的消息都进入 default 队列.
Queue('task1_app',exchange=Exchange('task1'), routing_key="task1.#") # 路由键 以 "web." 开头的消息都进入 task1队列.
)
- CELERY_ROUTES 自定义任务路由
CELERY_ROUTES = {
'celery_app.app_task1.auto_crawl':{'queue':'task1','routing_key':'task1'},
'celery_app.app_task1.auto_download':{'queue':'task1','routing_key':'task1'},
'celery_app.app_task1.timelycrawl': {'queue': 'task2', 'routing_key': 'task2'},
'celery_app.app_task1.timelydownload': {'queue': 'task2', 'routing_key': 'task2'}
}
- CELERY_ACCEPT_CONTENT 指定过任务接受内容的格式
CELERYBEAT_SCHEDULE = {
'add': {
'task': 'proj.tasks.add', #任务的路劲
'schedule': timedelta(seconds=10), #定时启动时间,也可以用crontab
'args': (16, 16) #任务参数
}
Celery的存储问题
在使用定时任务的时候我发现了一个问题,就是当你有两个定时任务(task1,task2)时,两个的定时时间相同比如都是一分钟,
然后task1的执行时间较长要2分钟,而task2的执行时间只要两秒,理想状态下是task1在执行但因为时间较长,会挂起,然后在挂起的时间里定时的去执行task2。但实际情况下,当进行task1的时候,在task1未执行完的时候,task2并不执行,然后当task1执行完时,task2会立马执行好几次。
下图就是,celery的流程:
image.png
从该图可以看出,造成该原因的是因为只有一个Woker,在从任务队列里面拿出一个任务时,在没执行完当前任务的时候是不会在往任务队列里面拿去任务,但task2在每两秒内会往该任务队列里面放入任务,所以根据队列先进先出的原则,在task1执行完时,会立马执行好几次的task2
解决方案:
image.png
解决的方法就是,增加并发数,也就是在设置里面添加CELERYD_CONCURRENCY参数,每个woker在闲空的时候就会自动去任务队列里面拿任务就不会造成任务阻塞。
所以定时任务最好不要放多个互相之间有依赖关系的任务