【Celery】Django项目celery异步的使用

原文作者:我辈李想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。



前言

Django 是一个基于 Python 的 Web 开发框架,而 Celery 是一个 Python 实现的异步任务队列(Task Queue),它能够处理大规模的分布式任务,用于实现 Django 中的异步任务。

使用 Celery 和 Django 可以实现以下功能:

  1. 异步任务处理:Celery 可以将耗时的任务异步处理,加速 Web 应用的响应速度。

  2. 定时任务:Celery 可以通过设置定时任务,定期执行某些任务,例如定时清理数据库。

  3. 异常处理:Celery 可以在任务执行失败时捕获异常,并进行相应的处理,例如发送邮件通知管理员。

  4. 分布式任务:Celery 可以将任务分发到多个节点进行处理,提高任务执行效率和并发性。

在 Django 中使用 Celery,需要进行以下几个步骤:

  1. 安装 Celery 和消息队列(例如 RabbitMQ、Redis 等)。

  2. 在 Django 中配置 Celery。

  3. 定义任务函数,并使用 Celery 的装饰器进行装饰。

  4. 在 Django 视图函数中调用任务函数,并将任务加入 Celery 队列执行。

  5. 监控 Celery 任务执行状态和日志。


一、安装 Celery

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple celery==5.3.1

Celery 的4大重点,task、Broker、worker、bacend

二、消息队列(Broker)

celery支持的消息队列常用的是RabbitMQ、Redis 等。这里就以Redis为例进行说明。

Redis的安装和使用

三、Django配置celery

1.创建celery_config.py文件

在django的settings.py同级目录添加celery_config.py,纤细配置参考celery官网配置

# -*- coding: utf-8 -*-
"""
@author:lpf
@file: celery_config.py
@time: 2023/8/7  17:17
"""
# 启用 UTC 时区
import os
from datetime import timedelta

# 时区,与django的TIMEZONE一致
CELERY_TIMEZONE = "Asia/Shanghai"

CELERY_TASK_TRACK_STARTED = True

# 有些情况防止死锁
CELERYD_FORCE_EXECV = True
# 任务失败允许重试
CELERY_ACKS_LATE = True
# Worker并发数量,一般默认CPU核数,可以不设置
CELERY_WORKER_CONCURRENCY = 2  # CELERYD_CONCURRENCY = 4
# 每个worker最多执行的任务数,超过这个就将worker进行销毁,防止内存泄漏,默认无限
CELERYD_MAX_TASKS_PER_CHILD = 100
# 单个任务运行的最大时间,超过这个时间,task就会被kill
CELERY_TASK_TIME_LIMIT = 30 * 60
# 过期时间,默认一天
CELERY_RESULT_EXPIRES = 30 * 60
# 任务限流
# CELERY_TASK_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}

# 定时任务
CELERYBEAT_SCHEDULE = {
    'task1': {
        'task': 'upload-task',  # 指定任务名称
        'schedule': timedelta(seconds=5),  # 任务执行时间,每5秒执行一次
        'options': {
            'queue': 'beat_tasks' # 指定队列
        }
    }
}

celery的其他参数请自行查阅celery官网

2.创建mycelery.py文件

# -*- coding: utf-8 -*-
"""
@author:lpf
@file: celery.py
@time: 2023/7/27  17:22
"""
import os

from celery import Celery

# 设置django环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tianyiapi.settings') # 项目配置

# 创建celery实例化对象
app = Celery('tianyiapi')   # 项目名

# 启动项目celery配置
app.config_from_object('django.conf:settings', namespace='CELERY')

# 自动发现项目中的tasks
app.autodiscover_tasks()

3.修改__init__.py文件

from .mycelery import app as celery_app

__all__ = ('celery_app',)

4.settings文件添加配置

# 配置 Celery
from .mycelery import *

# 指定 Broker 使用 Redis,Broker 负责任务的分发和调度
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/1'
# 指定结果存储 Backend 使用 Redis,Backend 负责存储任务执行结果
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
# django-celery-results 设置
CELERY_RESULT_BACKEND = 'django-db'

4.编写自己的task任务

django项目都是有很多app的(通过startapp命令创建),我们需要在app文件下新建tasks.py文件

from celery import shared_task

@shared_task
def send_email(to, subject, message):
    # 发送邮件代码

5.celery调用

celery调用主要有delay和apply_async两种方式,其中delay可设置参数较少,apply_async可以设置延时、过期等。

# delay方法+参数
task_name.delay(args1, args2, kwargs=value_1, kwargs2=value_2)# apply_async+参数
task.apply_async(args=[arg1, arg2], kwargs={key:value, key:value})

# apply_async+设置
add.apply_async((1, 2), queue='lopri', countdown=60, expires=120,ignore_result=True)  # 使用lopri队列,距现在60秒后开始执行,两分钟后过期,忽略结果

示例:

from django.shortcuts import render
from .tasks import send_email

def contact(request):
    # 处理表单提交

    # 将任务加入队列
    send_email.delay(to, subject, message)

    return render(request, 'contact.html', {'success': True})

4和5使用 @shared_task 装饰器定义了一个 send_email 异步任务,然后在 Django 视图函数中调用该任务,并使用 delay() 方法将任务加入 Celery 队列执行。

注意,在使用 Celery 进行异步任务处理时,需要注意任务的并发性和任务的执行结果。为了提高任务的并发性,可以将任务分发到多个节点进行执行;为了获取任务的执行结果,可以使用 Celery 提供的结果存储和状态监控功能。

6、celery重试

我们在使用celery时,可能因为各种原因存在问题,导致程序没有按照我们制定的方式运行,对于有些任务,我们就需要继续执行。Celery提供了一些方法来处理任务失败和重试,可以在任务失败时自动重试或手动重试。

方式一:shared_task中重试

from celery import shared_task

@shared_task
def my_task(*args, **kwargs):
    try:
        # 执行任务
    except Exception as exc:
        # 引发重试
        raise my_task.retry(exc=exc, countdown=60, max_retries=10)
 

在上述代码中,当任务执行发生异常时,会引发一个重试,参数说明如下:

exc:异常对象,用于调试错误;
countdown:重试之前的倒计时,以秒为单位;
max_retries:重试的最大次数。

以上例子中,每次重试之间的间隔为60秒,最多重试10次。

方式二:app.task装饰器设置重试

当使用 bind=True 参数之后, 函数的参数发生变化, 多出了参数 self, 这这相当于把 div 编程了一个已绑定的方法, 通过 self 可以获得任务的上下文.。在定义任务时,可以设置一些参数来实现自动重试。例如:

@app.task(bind=True, max_retries=3, default_retry_delay=10)
def my_task(self, *args, **kwargs):
    try:
        # 执行任务
    except Exception as exc:
        raise self.retry(exc=exc)

这个任务被设置为最大重试3次,每次重试间隔10秒钟。如果任务执行时出现异常,会自动引发重试任务。

方式三:Task继承

这种方式没怎么用过,需要的可以好好研究。

import celery
import time
from django.core.mail import send_mail
from celery.utils.log import get_task_logger
from wedo import app
 
logger = get_task_logger(__name__)

class TaskMonitor(celery.Task):
    def on_failure(self, exc, task_id, args, kwargs, einfo):
        """failed callback"""
        info=f'任务失败-- task id:{task_id} , arg:{args} , failed ! erros: {exc}'
        logger.info(info)
        send_mail('celery任务监控异常', info, 'sendmail@qq.com', ['tomail@qq.com'])
 
    def on_success(self, retval, task_id, args, kwargs):
        """success callback"""
        logger.info('task id:{} , arg:{} , successful !'.format(task_id,args))
 
    def on_retry(self, exc, task_id, args, kwargs, einfo):
        """retry callback"""
        logger.info('task id:{} , arg:{} , retry !  einfo: {}'.format(task_id, args, exc))
 
# @shared_task(base=TaskMonitor, bind=True)
@app.task(base=TaskMonitor, bind=True, name='post_file')
def post_file(self, file_names):
    logger.info(self.request.__dict__)
    try:
        # 执行任务
    except Exception as exc:
        raise self.retry(exc=exc, countdown=60, max_retries=10)

这个自定义任务类可以手动引发重试,设置最大重试次数和计数器。

需要注意的是,自动重试和手动重试都可能导致无限循环重试的问题。在处理任务失败和重试时,一定要谨慎处理。

7.日志

from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

@app.task
def add(x, y):
    logger.info('Adding {0} + {1}'.format(x, y))
    return x + y

8.队列(未证实)

# apply_async+设置
add.apply_async((1, 2), queue='lopri', countdown=60, expires=120,ignore_result=True)  # 使用lopri队列,距现在60秒后开始执行,两分钟后过期,忽略结果

四、celery启动和停止(Worker)

1.windows启动celery

在命令行中进入Python脚本所在的目录,然后执行以下命令启动Celery worker:

celery -A tasks worker --loglevel=info

这里的-A参数表示要加载的Celery应用模块,worker表示启动worker进程,--loglevel表示日志级别。

2.linux启动celery

3.停止

celery multi stop w1 -A proj -l info
# linux
ps auxww | grep 'celery worker' | awk '{print $2}' | xargs kill -9

五、celery监控

1.Flower监控

  1. 安装

     pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flower
    
  2. 启动

     celery -A  项目名 flower --address=127.0.0.1 --port=5555
    

2.django-celery-result监控

文档地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要通过CeleryDjango启用异步类视图,您需要执行以下步骤: 1. 首先,确保已经安装了CeleryDjango-Celery包。您可以使用以下命令来安装它们: ``` pip install celery django-celery ``` 2. 在Django项目的settings.py文件,添加以下配置: ```python # Celery配置 CELERY_BROKER_URL = 'redis://localhost:6379' CELERY_RESULT_BACKEND = 'redis://localhost:6379' ``` 这里使用了Redis作为消息代理和结果后端,您可以根据需要选择其他选项。 3. 创建一个名为`tasks.py`的文件,并在其定义您的Celery任务。例如: ```python from celery import shared_task @shared_task def your_async_task(*args, **kwargs): # 执行异步任务的代码逻辑 pass ``` 4. 在您的类视图使用`@method_decorator`装饰器将`@shared_task`应用于您要异步执行的方法。例如: ```python from django.utils.decorators import method_decorator from yourapp.tasks import your_async_task class YourAsyncView(View): @method_decorator(your_async_task.delay) def post(self, request, *args, **kwargs): # 执行您的视图逻辑 pass ``` 这样,每当您调用此类视图的POST方法时,它将在后台异步执行`your_async_task`任务。 5. 启动Celery工作进程。在终端,导航到您的项目目录并运行以下命令: ``` celery -A yourprojectname worker --loglevel=info ``` 这将启动一个Celery工作进程,准备接收和执行异步任务。 现在,当您访问包含上述类视图的URL并发送POST请求时,该请求将被异步处理,而不会阻塞主线程。请确保您的Celery工作进程正在运行,并根据需要进行其他配置和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我辈李想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值