Django 3 + Celery 5 + redis 配合使用
配置
Django 3.x 项目配置Celery之后树图大概是这样的:
- 根目录文件夹
- config (项目名称文件夹,本来是根据你创建项目时候的名字的,这里我改名为config,注意下面配置文件的路径)
- _init_.py
- asgi.py
- settings.py
- urls.py
- wsgi.py
- celeryCenter.py
- celeryConfig.py
- APP
- _init_.py
- admin.py
- apps.py
- models.py
- tests.py
- views.py
- tasks.py
- manage.py
- config (项目名称文件夹,本来是根据你创建项目时候的名字的,这里我改名为config,注意下面配置文件的路径)
配置安装
- 安装Celery,如果使用reids,也要一起安装 reids官网 https://redis.io/download/
- pip install celery
- pip install reids
1.celeryConfig.py
# 使用redis来做消息中间件
# 任务存储
#redis有密码的话
#result_backend = r'redis://:password@127.0.0.1:6379/0'
broker_url = r'redis://127.0.0.1:6379/0'
# 结果存储
result_backend = r'redis://127.0.0.1:6379/0'
# 使用rebbitmq来做消息中间件
# 默认是使用guest账号来登录的
# broker_url = 'amqp://guest:guest@localhost:5672//'
# broker_url = 'amqp://admin:admin@192.168.10.1:5672//'
# result_serializer = 'json'
# 时区
timezone = 'Asia/Shanghai'
# 过期时间
# event_queue_ttl = 5
# celery不回复结果
task_ignore_result = False
# 为防止内存泄漏,一个进程执行过N次之后杀死,建议是100次
worker_max_tasks_per_child = 10
# 错误 DatabaseWrapper objects created in a thread can only be used in that same thread
CELERY_TASK_ALWAYS_EAGER = True
2.celeryCenter.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# 设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
# 注册Celery的APP
app = Celery('name')
# 绑定配置文件
app.config_from_object("config.celeryConfig")
# 自动发现各个app下的tasks.py文件
app.autodiscover_tasks()
3.config/_init_.py
# 使用celery的设置
from __future__ import absolute_import, unicode_literals
# 固定写法(使用的是MYSQL数据库的话)
import pymysql
pymysql.install_as_MySQLdb() # 告诉django用pymysql代替mysqldb连接数据库
# 自动导入Django的app下面的tasks文件内的函数
__all__ = ['celery_app']
任务和任务执行
- 由于已经设置导入所有APP下的tasks.py文件,所以我们直接在该文件编写任务
app/tasks.py
from config.celeryCenter import app as celeryApp
import celery
# 创建任务 使用修饰器的方式,需要注意的一点是,当函数有多个装饰器时,为了保证 Celery 的正常运行,celeryApp.task 装饰器需要在最外层
# 参数作用: name : 方法名(执行方法时用到的)
# bind 为True的时候, 则会为这个任务绑定一个 Task 实例,通过第一个 self 参数传入,可以通过这个 self 参数访问到 Task 对象的所有属性
# base 以通过继承 celery.Task 的方式来定义自己的 Task 类,并为你的 Task 类添加额外的功能,例如执行成功时做什么,失败时做什么
'''
- after_return:在任务执行返回后交给 worker 执行
- on_failure:在任务执行失败后交给 worker 执行
- on_retry:在任务进行重试是交给 worker 执行
- on_success:在任务执行成功后交给 worker 执行
'''
#自定义任务执行状态方法
class MyTask(celery.Task):
#重写执行成功方法
def on_success(self, retval, task_id, args, kwargs):
print(f'{task_id}执行完成')
#重写执行失败方法
def on_failure(self, exc, task_id, args, kwargs, einfo):
print(f'{task_id}执行失败,错误信息{exc}')
@celeryApp.task(name = 'taskName',bind = True,base = MyTask)
def taskFunction(self,param1,param2):
print('执行任务')
print(self.request.id)
status = False
if status :
#跳去执行成功方法
return '执行成功'
else:
#跳去执行失败方法
raise Exception('执行失败')
- 执行任务,多数在各个APP下的views.py执行的了
app/views.py
通过 delay 使用 Celery 执行一个任务,实际上 delay 是 apply_async 的一个快捷方式,而相较于 delay,apply_aysnc 支持对于任务执行过程的更精确的控制。比如下面这个例子的 countdown 参数表示在接收到任务 10 秒后开始执行
from config.celeryCenter import app as celeryApp
from app.tasks import taskFunction
taskObj = celeryApp.send_task('taskName',[param1,param2],countdown=10)
taskObj = taskFunction.apply_async([param1,param2],countdown=10)
<AsyncResult: ee1315a5-858b-40b9-98de-995254eb0fe2>
#通过ready()获取任务是否完成状态
while not taskObj.ready():
print('正在执行')
time.sleep(1)
'''
在 Celery 中执行任务的方法一共有三种:
1. delay, 用来进行最简单便捷的任务执行;
2. apply_async, 对于任务的执行附加额外的参数,对任务进行控制;
3. app.send_task, 可以执行未在 Celery 中进行注册的任务。
'''
启动任务
在项目根目录下输入命令行
#运行成功最后会在终端显示 celery@PC-xxxx123BOGP ready.
DjangoProject> celery -A config.celeryCenter worker --pool=solo --loglevel=INFO
定时任务和定时任务执行
- 启动定时任务可以通过以下方式配置
1,配置文件指定
2,程序文件指定
1,配置文件指定
# django项目名/django项目名/celeryCenter.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# 设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
# 注册Celery的APP
app = Celery('wenyoujia')
# 绑定配置文件
app.config_from_object("config.celeryConfig")
# 自动发现各个app下的tasks.py文件
app.autodiscover_tasks()
#定时任务方法
@app.task(name = 'printMsg')
def printMsgFun(message,info):
print(f'执行定时任务{message}')
print(f'字典参数{info}')
return 'OK'
#定时任务
app.conf.beat_schedule = {
'timingName': { #定时任务名
'task': 'printMsg', #方法名
'schedule': 5, #间隔执行秒数
'args': ('Hello World',), #列表参数
'kwargs':{ #字典参数
'info': {
'data':'hello data'
}
}
},
}
2,程序文件指定,需要手动调用(以下例子我是在app的tasks.py指定定时任务,views.py执行)
tasks.py
from config.celeryCenter import app as celeryApp
from celery.schedules import crontab
@celeryApp.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
# 五秒一次执行
sender.add_periodic_task(5, test.s('5s,do'))
# 每周二早上9点45分执行
sender.add_periodic_task(
crontab(hour=9, minute=45, day_of_week=2),
test.s('Tuesday,do'),
)
@celeryApp.task
def test(arg):
print(arg)
views.py
from config.celeryCenter import app as celeryApp #导入实例
from backstage_api.tasks import setup_periodic_tasks #导入方法
setup_periodic_tasks(celeryApp)
print('执行定时任务')
- Celery 提供了一个 crontab 的对象,可以对于执行定时任务的周期时间精准设置。
from celery.schedules import crontab
# 每分钟执行一次
c1 = crontab()
# 每天凌晨十二点执行
c2 = crontab(minute=0, hour=0)
# 每30分钟执行一次
crontab(minute='*/30')
# 每周二的每一分钟执行一次
crontab(minute='*',hour='*', day_of_week=2)
# 每周二,四的五点,十六点和二十点每十二分钟执行一次
crontab(minute='*/12',hour='5,16,20', day_of_week=2,4)
启动定时任务
在项目根目录下输入命令行
#运行成功最后会在终端显示 beat: Starting...
DjangoProject> celery -A config.celeryCenter beat --loglevel=INFO
#linxu下开启守护进程,需要进入项目虚拟环境运行
nohup celery -A config.celeryCenter worker --pool=solo --loglevel=INFO -B &
#宝塔py项目管理器2.0运行celery,进入项目根目录
nohup /www/wwwroot/proDIr/xxxxx_venv/bin/celery -A config.celeryCenter worker --pool=solo --loglevel=INFO -B &