django中使用celery
通用方案
将自定义的celery的包拉到django项目根目录
在celery.py文件内导入django的环境变量
这样才能正常启动worker或者beat
from celery import Celery
import time
import os
# 必须要将django的环境变量加进去(在manage.py中复制)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
# 消息中间件
broker = 'redis://127.0.0.1:6379/1'
# 结果存储
backend = 'redis://127.0.0.1:6379/2'
# 1 创建app对象
app = Celery('app', broker=broker, backend=backend, include=['celery_task.order_task', 'celery_task.user_task'])
最后在需要用到celery的地方导入对应的任务函数----》提交任务
from celery_task.user_task import celery_send_sms, celery_add
from datetime import datetime, timedelta
class CeleryView(APIView):
def get(self, request):
# 异步发短信
mobile = request.query_params.get('mobile')
code = get_code()
# 使用celery 异步提交任务
res = celery_send_sms.delay(mobile=mobile, code=code)
return APIResponse(msg=f'短信已发送{str(res)}')
def post(self, request):
x = request.data.get('x')
y = request.data.get('y')
eta = datetime.utcnow() + timedelta(seconds=10)
res = celery_add.apply_async(args=(x, y), eta=eta)
return APIResponse(msg=f'计算结果为{res}')
官方推荐的方案
【1】安装模块
# 1 安装模块
pip install Django==3.2.22
pip install celery
pip install redis
pip install eventlet #在windows环境下需要安装eventlet包
【2】创建celery.py
在项目内层根目录下创建celery.py
配置内容
import os
import django
from celery import Celery
from django.utils import timezone
# 为celery设置环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
django.setup()
# 创建app
app = Celery('celery_demo')
# 会自动从django的配置文件中导入celery配置项
# 这里namespace配置之后,配置文件里面的celery配置项都需带上CELERY前缀 如下图
app.config_from_object('django.conf:settings', namespace='CELERY')
# 会自动检索django每个app下的task.py 里的函数作为任务
app.autodiscover_tasks()
# 解决时区问题,定时任务启动就循环输出
app.now = timezone.now
django的配置文件
# django配置文件.py
# celery配置项
# Broker配置,使用Redis作为消息中间件
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/1'
# BACKEND配置,这里使用redis
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/2'
# 结果序列化方案
CELERY_RESULT_SERIALIZER = 'json'
# 并发任务数worker数量
CELERYD_CONCURRENCY = 20
# 每个worker最大执行任务数
CELERYD_MAX_TASKS_PER_CHILD = 20
更多配置
# 为django_celery_results存储Celery任务执行结果设置后台
# 格式为:db+scheme://user:password@host:port/dbname
# 支持数据库django-db和缓存django-cache存储任务状态及结果
CELERY_RESULT_BACKEND = "django-db"
# celery内容等消息的格式设置,默认json
CELERY_ACCEPT_CONTENT = ['application/json', ]
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
# 为任务设置超时时间,单位秒。超时即中止,执行下个任务。
CELERY_TASK_TIME_LIMIT = 5
# 为存储结果设置过期日期,默认1天过期。如果beat开启,Celery每天会自动清除。
# 设为0,存储结果永不过期
CELERY_RESULT_EXPIRES = xx
# 任务限流
CELERY_TASK_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}
# Worker并发数量,一般默认CPU核数,可以不设置
CELERY_WORKER_CONCURRENCY = 2
# 每个worker执行了多少任务就会死掉,默认是无限的
CELERY_WORKER_MAX_TASKS_PER_CHILD = 200
【3】修改__init__.py
配置与celery.py同级的__init__.py
文件
from .celery1 import app as celery_app
__all__ = ['celery_app']
【4】建立tasks.py
在某个app下创建task.py,写对应的功能
注意,这个文件必须要tasks.py
例子
# 导入装饰器函数 shared_task
from celery import shared_task
@shared_task
def add(a, b):
return a + b
【5】视图函数使用
from rest_framework.views import APIView
from utils.common_response import APIResponse
#导入task.py里面的任务函数
from .task import add
class CeleryTestView(APIView):
def post(self, request):
x = request.data.get('x')
y = request.data.get('y')
res = add.delay(x, y)
return APIResponse(msg=f'执行了:>>>{str(res)}')
异步调用任务两种方法
# 方法一:delay方法
task_name.delay(args1, args2, kwargs=value_1, kwargs2=value_2)
# 方法二: apply_async方法,与delay类似,但支持更多参数
task.apply_async(args=[arg1, arg2], kwargs={key:value, key:value})
【6】启动worker
要注意项目名导入时的路径
因为它是基于环境变量导入的
所以要加上luffy_api
celery -A luffy_api.celery1 worker -l debug -P eventlet
补充(定时提交任务)
在celery.py添加配置
CELERY_BEAT_SCHEDULE = {
'every_1_minutes': {
'task': 'luffy_api.apps.home.task.add', #
'schedule': timedelta(seconds=2),
'args': ()
},
}
celery -A luffy_api.celery1 worker -l debug -P eventlet
celery -A luffy_api.celery1 beat -l debug
app.task和shared_task区别
1 两个装饰器的区别
# @app.task(bind=True)装饰器:
这是Celery库中的装饰器,用于将函数注册为Celery任务。
bind=True指定任务函数的第一个参数为任务实例本身(通常命名为self),允许您在任务函数内部访问任务实例的属性和方法。
# @shared_task(bind=True)装饰器:
这是Celery的另一个装饰器,用于将函数注册为共享任务(shared task)。
共享任务是一种特殊类型的任务,可以跨多个Celery应用程序共享和调用。
如果您的任务需要在多个Celery应用程序中共享,或者您希望使用共享任务的特性,那么可以考虑使用此装饰器。
# 使用建议
哪个装饰器更好取决于您的具体需求和使用情况:
如果您只是在单个Celery应用程序中定义和使用任务函数,那么@app.task(bind=True)装饰器可能更适合。
如果您需要共享任务或跨多个Celery应用程序使用任务,那么@shared_task(bind=True)装饰器可能更适合。