Loading

django中使用celery

通用方案

将自定义的celery的包拉到django项目根目录

image-20240516200645444

在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

image-20240516222208005

配置内容

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的配置文件

image-20240516222345809

# 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)装饰器可能更适合。
posted @ 2024-05-18 12:35  HuangQiaoqi  阅读(32)  评论(0编辑  收藏  举报