最近工作之余,记录一下自己的笔记,首先来介绍一下celery
(一)、为什么要使用celery,业务场景
1、我们平时工作中,经常会碰到一个视图里面写了很多逻辑,导致里面有一些很耗时的操作,比如发送邮件、短信之类的操作,这些我们一般是调用第三方sdk去做的,通常客户端接收响应需要等待,降低了服务器的吞吐量及性能
2、服务器难免会有定时任务的需求,比如用户数据更新,缓存清除等等
(二)、celery介绍
为了解决以上问题,我们可以使用celery
Celery是一个功能完备即插即用的任务队列。
celery适用异步处理问题,当发送邮件、或者文件上传, 图像处理等等一些比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用户体验。 celery的特点是:
1、简单,易于使用和维护,有丰富的文档。
2、高效,单个celery进程每分钟可以处理数百万个任务。
3、灵活,celery中几乎每个部分都可以自定义扩展。
celery主要通过消息进行通信,通常使用一个叫Broker(中间人)来协调client(任务的发出者)和worker(任务的处理者). clients发出消息到队列中,broker将队列中的信息派发给worker来处理。
以下是某网站截图,图文表达更清楚一些

Celery需要一种解决消息的发送和接受的中间装置叫做消息中间人。
本文使用的是redis来做中间人,django+celery+redis来实现简单的异步和定时
话不多说,直接上代码,代码中都上了注释
# import re
# from datetime import timedelta
from celery.schedules import crontab
from kombu import Queue
from celery_tasks.main import app
# 配置代理人,指定代理人将任务存到哪里,这里是redis的14号库
broker_url = 'redis://127.0.0.1:6379/14'
# celery worker的并发数,默认是服务器的内核数目,也是命令行-c参数指定的数目
# CELERYD_CONCURRENCY = 8
worker_concurrency = 8
# celery worker 每次去BROKER中预取任务的数量-
worker_prefetch_multiplier = 4
# 每个worker执行了多少任务就会死掉,默认是无限的,释放内存
worker_max_tasks_per_child = 200
# 任务结果保存时间
worker_task_result_expires = 60 * 60 * 2
# 非常重要,有些情况下可以防止死锁
worker_force_execv = True
# 任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行
worker_disable_rate_limits = True
# 读取任务结果一般性能要求不高,所以使用了可读性更好的JSON
worker_result_serializer = "json"
# CELERY_TASK_DEFAULT_QUEUE = "default" # 默认队列
worker_task_default_queue = "default"
task_queues = (
Queue("default", routing_key="default"),
Queue("base", routing_key="base.#"),
)
task_routes = {
# res = tasks.test.apply_async(queue='default', routing_key='default')
# 以上如果指定队列执行,则下列指定方式失效
"test": {
'queue': 'base', 'routing_key': 'base.info'},
# "test1": {'queue': 'base', 'routing_key': 'base.test'},
}
# 定义默认队列和默认的交换机routing_key
task_default_queue = 'default'
task_default_exchange = 'default'
task_default_routing_key = 'default'
# 设置时区,默认UTC
timezone = 'Asia/Shanghai'
main.py
import os, logging
from datetime import timedelta
from config import settings
from celery import Celery
logger = logging.getLogger(settings.LOGGER_DEVICE_MANAGE)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
# 创建celery应用
app = Celery('test')
# 导入celery配置
app.config_from_object('celery_tasks.config')
# 自动注册celery任务
# 在指定的包中找tasks.py文件,在这个文件中找@app.task的函数,当做任务
# app.autodiscover_tasks() # 自动
# 定时任务需要添加
app.autodiscover_tasks(['celery_tasks.base_info'])
# # 在出现worker接受到的message出现没有注册的错误时,使用下面一句能解决
imports = ("tasks",)
最基本的配置已经完成
然后关于任务的逻辑编写,我们可以在celery_tasks下面新建一个文件夹,叫base_info,再在base_info下面新建一个任务tasks.py,然后需要执行什么任务直接在tasks.py里面写逻辑,这里举例是微信模板消息通知
import logging
from celery_tasks.main import app
# from util.sql_query import sql_query
from config import settings
from util import wechat
logger = logging.getLogger(settings.LOGGER_DEVICE_MANAGE)
@app.task(name='test')
def test():
msg_ob = wechat.WechatAssistantMsg()
res = msg_ob.send_msg(['33742'], '异步任务执行')
logger.info(res)
然后一定要记得启动celery,这个是独立启动的
切记在celery_tasks目录的上级目录下启动
命令celery -A celery_tasks.main worker -B -l info --beat (默认是启动定时任务及异步任务)

我们看到celery已经启动了,接下来我们启动django,在django中编写view.py

然后我们通过postman调用这个test接口,就可以看到celery控制台输出任务信息,执行成功

定时任务的配置
在config.py中只需添加以下代码
from celery.schedules import crontab
# 设置定时任务
app.conf.beat_schedule = {
"test_task": {
"task": "test",
"schedule": crontab(hour=11, minute=28),# 每天的11点28分执行一次任务
}
}
其中的"task": “test”, test为你需要执行的函数(任务)名

完成
使用supervisor管理celery
其中supervisor配置如下
[program:celery_worker]
command=/root/install/server/bin/celery -A celery_tasks.main worker -B -l info --beat
directory=/root/data/system/server_system
user=root
numprocs=1
stdout_logfile=/root/data/supervisor_celery.log
autorestart=true
startsecs=10
redirect_stderr=true
loglevel=info
redirect_stderr = true ; 把 stderr 重定向到 stdout,默认 false
; Need to wait for currently executing tasks to finish at shutdown.
; Increase this if you have very long running tasks.
stopwaitsecs = 600
; Set Celery priority higher than default (999)
; so, if rabbitmq is supervised, it will start first.
priority=1000
然后重启supervisor即可,我们可以通过supervisorctl客户端看到多了一个任务进程

supervisor报错可以结合我上一篇文章
如有任何疑问,欢迎留言