celery详解(使用django+celery实现异步及定时任务以及使用supervisor进行管理)

最近工作之余,记录一下自己的笔记,首先来介绍一下celery

(一)、为什么要使用celery,业务场景

1、我们平时工作中,经常会碰到一个视图里面写了很多逻辑,导致里面有一些很耗时的操作,比如发送邮件、短信之类的操作,这些我们一般是调用第三方sdk去做的,通常客户端接收响应需要等待,降低了服务器的吞吐量及性能

2、服务器难免会有定时任务的需求,比如用户数据更新,缓存清除等等

(二)、celery介绍

为了解决以上问题,我们可以使用celery
Celery是一个功能完备即插即用的任务队列。
celery适用异步处理问题,当发送邮件、或者文件上传, 图像处理等等一些比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用户体验。 celery的特点是:
1、简单,易于使用和维护,有丰富的文档。
2、高效,单个celery进程每分钟可以处理数百万个任务。
3、灵活,celery中几乎每个部分都可以自定义扩展。

celery主要通过消息进行通信,通常使用一个叫Broker(中间人)来协调client(任务的发出者)和worker(任务的处理者). clients发出消息到队列中,broker将队列中的信息派发给worker来处理。

以下是某网站截图,图文表达更清楚一些
celery详解(使用django+celery实现异步及定时任务以及使用supervisor进行管理)_第1张图片
Celery需要一种解决消息的发送和接受的中间装置叫做消息中间人。
本文使用的是redis来做中间人,django+celery+redis来实现简单的异步和定时

话不多说,直接上代码,代码中都上了注释

我的目录结构
celery详解(使用django+celery实现异步及定时任务以及使用supervisor进行管理)_第2张图片
config.py

# 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+celery实现异步及定时任务以及使用supervisor进行管理)_第3张图片
我们看到celery已经启动了,接下来我们启动django,在django中编写view.py
celery详解(使用django+celery实现异步及定时任务以及使用supervisor进行管理)_第4张图片
然后我们通过postman调用这个test接口,就可以看到celery控制台输出任务信息,执行成功
celery详解(使用django+celery实现异步及定时任务以及使用supervisor进行管理)_第5张图片

定时任务的配置

在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为你需要执行的函数(任务)名
celery详解(使用django+celery实现异步及定时任务以及使用supervisor进行管理)_第6张图片
完成

使用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报错可以结合我上一篇文章

如有任何疑问,欢迎留言

你可能感兴趣的:(笔记,python,django,后端)