关于为什么要用或者说有点就不写了。简单来说好用,就是干
看了这个图简直精髓啊原理:
任务模块Task包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发并发往消息队列,而定时任务由Celery Beat进程周期性地将任务发往消息队列;
任务执行单元Worker实时监视消息队列获取队列中的任务执行;
Woker执行完任务后将结果保存在Backend中;
消息中间件值得一看
消息中间件Broker官方提供了很多备选方案,支持RabbitMQ、Redis、Amazon SQS、MongoDB、Memcached 等,官方推荐RabbitMQ。
存储的话,redis,异步Mongo,es都是不错的选择,简单用大佬的一句话:天下武功为快不破
好了正题正题咳咳
配置项大概:
CELERY_DEFAULT_QUEUE:默认队列
BROKER_URL = 'redis://localhost:6379/1' #代理队列
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 43200,'fanout_prefix': True}
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'#结果存储队列##可以先redis在起个持久化到sql或MongoDB的队列
CELERY_TASK_SERIALIZER = 'json' #任务序列化方式
CELERY_RESULT_SERIALIZER = 'json' #结果序列化方式
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 # 任务过期时间
CELERY_ACCEPT_CONTENT = ["json"] #指定任务接收的内容类型
CELERY_TIMEZONE='Asia/Shanghai' # 时区配置,这个没用过
CELERY_IMPORTS = ( # 指定导入的任务模块,可以指定多个##这个貌似有点问题一会贴
'project.tasks',
)
from kombu import Queue
CELERY_QUEUE = ( # 定义任务队列.
Queue('default', routing_key="task.#"),
# 路由键 以 "task." 开头的消息都进入 default 队列.
Queue('web_tasks', routing_key="web.#")
# 路由键 以 "web." 开头的消息都进入 web_tasks 队列.
)
CELERY_DEFAULT_EXCHANGE = 'tasks'
# 默认的交换机名字为 tasks
CELERY_DEFAULT_EXCHANGE_KEY = 'topic'
# 默认的交换机类型为 topic
CELERY_DEFAULT_ROUTING_KEY = 'task.default'
# 默认的路由键是 task.default , 这个路由键符合上面的 default 队列.
CELERY_ROUTES = {
'proj.tasks.add': {
'queue': 'web_tasks',
'routing_key': 'web.add',
}
}
# 使用指定队列的方式启动消费者进程.
celery -A proj worker -Q web_tasks -l info # 该 worker 只会执行 web_tasks 中任务, 我们可以合理安排消费者数量, 让 web_tasks 中任务的优先级更高.
# 修改配置文件, # 下面的任务指定 tasks.add 任务 每 10s 跑一次, 任务参数为 (16,16).
from datetime import timedelta
CELERYBEAT_SCHEDULE = {
'add': {
'task': 'proj.tasks.add',
'schedule': timedelta(seconds=10),
'args': (16, 16)
}}
# crontab 风格
from celery.schedules import crontab
CELERYBEAT_SCHEDULE = {
"add": {
"task": "tasks.add",
"schedule": crontab(hour="*/3", minute=12),
"args": (16, 16),
}
}
# 发生 ZeroDivisionError 错误时, 每 5s 重试一次, 最多重试 3 次大致如此
from celery.utils.log import get_task_logger
logger = get_task_logger(__name__)
@app.task(bind=True)
def div(self, x, y):
logger.info(('Executing task id {0.id}, args: {0.args!r}' 'kwargs: {0.kwargs!r}').format(self.request))
try:
result = x/y
except ZeroDivisionError as e:
raise self.retry(exc=e, countdown=5, max_retries=3)
好吧这有个专门介绍config的真的丰富[点着](https://blog.youkuaiyun.com/libing_thinking/article/details/78812472)
导入配置文件
from __future__ import absolute_import#涉及一个导包问题最好是导一下##py2不太兼容的问题
app = Celery(__name__, include=["task"])#第一个参数主文件去尾缀,这里也可以惊醒一些配置
# 引入配置文件
app.config_from_object(“config”)#配置文件
在实例化的之后起了项目报了个错
not enough values to unpack (expected 3, got 0)
解决办法下一个包eventlet,运行时参数改为:celery -A yourtasks#你自己的 worker -l info -P eventlet
大哥的方案
官方小函数task任务定义文件:
if __name__ == '__main__':
result = add.delay(30, 42)
# task.py
from main import app
@app.task
def add(x, y):
return x + y
将任务添加到worker中,并返回AsyncResult对象:
delay 实际上是 apply_async 的别名, 还可以使用如下方法调用, 但是 apply_async 支持更多的参数:
countdown : 等待一段时间再执行,默认立即执行,float
eta : 定义任务的开始时间,countdown参数设定eta就可以不存下.datetime.datetime
expires : 设置超时时间.float
retry : 定时如果任务失败后, 是否重试.#`task_publish_retry setting应该也是可以设置的
retry_policy字典
max_retries : 最大重试次数, 默认为 3 次.
interval_start : 重试等待的时间间隔秒数, 默认为 0 , 表示直接重试不等待.
interval_step : 每次重试让重试间隔增加的秒数, 可以是数字或浮点数, 默认为 0.2
interval_max : 重试间隔最大的秒数, 即 通过 interval_step 增大到多少秒之后, 就不在增加了, 可以是数字或者浮点数, 默认为 0.2
queue被启用的队列,str
exchange 用于发送任务。通常不与``队列一起使用``争论。
routing_key (str):用于将任务路由到的自定义路由键工作服务器。如果与“queue”参数组合使用仅用于指定主题交换的自定义路由密钥。
priority (int)优先级0到9之间
serializer (str)要使用的序列化方法。可以是“pickle”、“json”、“yaml”、“msgpack”或mod:`kombu.serialization.registry
compression (str)可选压缩方法使用。可以是“zlib”、“bzip2”之一,或注册的任何自定义压缩方法:func:`kombu.compression.register`。
link (Signature)一个或者list在成功回调方法
link_error (Signature)失败的回调方法
producer生产者
add_to_parent没有查到具体用法
publisher 生产者别名貌似弃用
headers (Dict)
还有些实用的检测参数函数通过delay返回值
r.info: 获取任务信息,默认为结果
r.task_id: 返回任务id,r.id
r.ready() # 查看任务状态,返回布尔值, 任务执行完成, 返回 True, 否则返回 False.
r.wait() # 等待任务完成, 返回任务执行结果,很少使用;
r.get(timeout=1) # 获取任务执行结果,可以设置等待时间,同时也可以收集异常,r.get(propagate=False)可以直接输出错误而不报错
r.result # 任务执行结果.
r.state # PENDING, START, SUCCESS,任务当前的状态
r.status # PENDING, START, SUCCESS,任务当前的状态
r.successful # 任务成功返回true
r.traceback # 如果任务抛出了一个异常,你也可以获取原始的回溯信息
send_task():可以发送未被注册的异步任务,即没有被celery.task装饰的任务
app.send_task("tasks.add",args=[3,4])#第一个参数必须是函数所在模块加上函数名
大多是一些重复性工作。写的不是很细致望见谅