Django Celery异步任务队列的实现
作者:严北 发布时间:2023-09-28 19:24:53
背景
在开发中,我们常常会遇到一些耗时任务,举个例子:
上传并解析一个 1w 条数据的 Excel 文件,最后持久化至数据库。
在我的程序中,这个任务耗时大约 6s,对于用户来说,6s 的等待已经是个灾难了。
比较好的处理方式是:
接收这个任务的请求
将这个任务添加到队列中
立即返回「操作成功,正在后台处理」的字样
后台消费这个队列,执行这个任务
我们按照这个思路,借助 Celery 进行实现。
实现
本文所使用的环境如下:
Python 3.6.7
RabbitMQ 3.8
Celery 4.3
使用 Docker 安装 RabbitMQ
Celery 依赖一个消息后端,可选方案有 RabbitMQ, Redis 等,本文选用 RabbitMQ 。
同时为了安装方便,RabbitMQ 我直接使用 Docker 安装:
docker run -d --name anno-rabbit -p 5672:5672 rabbitmq:3
启动成功后,即可通过 amqp://localhost 访问该消息队列。
安装并配置 Celery
Celery 是 Python 实现的工具,安装可以直接通过 Pip 完成:
pip install celery
同时假设当前我的项目文件夹为 proj ,项目名为 myproj ,应用名为 myapp
安装完成后,在 proj/myproj/ 路径下创建一个 celery.py 文件,用来初始化 Celery 实例:
proj/myproj/celery.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery, platforms
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproj.settings')
app = Celery('myproj',
broker='amqp://localhost//',
backend='amqp://localhost//')
# Using a string here means the worker don't have to serialize
# the configuration object to child processes.s
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
然后在 proj/myproj/__init__.py 中添加对 Celery 对象的引用,确保 Django 启动后能够初始化 Celery:
proj/myproj/__init__.py
from __future__ import absolute_import, unicode_literals
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ('celery_app',)
无其他特殊配置的话,Celery 的基本配置就是这些。
编写一个耗时任务
为了模拟一个耗时任务,我们直接创建一个方法,使其「睡」10s ,并将其设置为 Celery 的任务:
proj/myapp/tasks.py
import time
from myproj.celery import app as celery_app
@celery_app.task
def waste_time():
time.sleep(10)
return "Run function 'waste_time' finished."
启动 Celery Worker
Celery 配置完成,并且任务创建成功后,我们以异步任务的模式启动 Celery :
celery -A myproj worker -l info
注意到我强调了异步模式,是因为 Celery 除了支持异步任务,还支持定时任务,因此启动时候要指明。
同时要注意,Celery 一旦启动,对 Task(此处为 waste_time) 的修改必须重启 Celery 才会生效。
任务调用
在请求处理的逻辑代码中,调用上面创建好的任务:
proj/myapp/views.py
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .tasks import waste_time
@require_http_methods(["POST"])
def upload_files(request):
waste_time.delay()
# Status code 202: Accepted, 表示异步任务已接受,可能还在处理中
return JsonResponse({"results": "操作成功,正在上传,请稍候..."}, status=202)
调用 waste_time.delay() 方法后, waste_time 会被加入到任务队列中,等待空闲的 Celery Worker 调用。
效果
当我们发送请求时,这个接口会直接返回 {"results": "操作成功,正在上传,请稍候..."} 的响应内容而非卡住十秒,用户体验要好许多。
总结
用 Celery 处理这种异步任务是 Python 常用的方法,虽然实际执行成功耗时不变甚至有所增加(如 Worker 繁忙导致处理滞后),但是对于用户体验来说更容易接受,点击上传大文件后可以继续处理其他事务,而不需要在页面等待。
Celery 还有更多用法本文未介绍到,其文档已经非常详尽,有需要可直接参考。
参考
http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html
https://hub.docker.com/_/rabbitmq
来源:https://juejin.im/post/5d043d28e51d4510bf1d666e


猜你喜欢
- 主要有五个方面:一..HTML页面转UTF-8编码问题二.PHP页面转UTF-8编码问题三.MYSQL数据库使用UTF-8编码的问题四.JS
- 最近在做zabbix的数据库MySQL5.6升级5.7时,出现主从延迟问题,这个问题困扰了很久没有解决,昨天终于解决了,整理了一下整个排查过
- 这是一家游戏公司,他面试通过后 擅长的机试却没答出来,不过还是被录用了。这道题内容大概这样有条蛇它长度不固定,蛇头朝北顺时针盘旋着,请打印出
- 前言在论坛中回答了一个问题,导入csv 数据,并对导入的数据增加一个新的列date datetime。要求在10s内完成,200w行数据的导
- None是一个对象,而NULL是一个类型。Python中没有NULL,只有None,None有自己的特殊类型NoneType。None不等于
- 目录前言掘金的成长搬家命令行工具环境配置main.pycookie.jsongithub 地址前言最近不少写博客的朋友跟我反馈博客园的一些文
- 听说最近流行JQ风格的语法,不流行EXT风格了一.//ajax类fw=window.fw||{};fw.ajax = { &nbs
- 如下所示:# #### dict中将key相同的字典合并在一个对象里"""a = {"a"
- 写出来的效果图就是这样了:下面就更新一下全部的代码吧还是老样子先定义import pygame,sysimport ra
- 本篇主要讲述如何基于NUXT的validate方法实现表单的验证。将验证方法封装后,使用的时候只需像:rules="filter_
- 代码如下:<% set rs=server.createobject("adodb.recordset&
- 前言众所周知在Python中有专门用于logger打印的套件叫logging,但是该套件logger仅接收一个字符串类型的logger打印信
- 使用邻接矩阵实现图及Dijkstra算法# 邻接矩阵实现无向图 Dijkstra算法inf = float("inf")
- 功能是从客户端向服务发送一个字符串, 服务器收到后将字符串重新发送给客户端,同时,在连接建立之后,服务器可以向客户端发送任意多的字符串客户端
- 前言python数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值,将重新分配内存空间。下面话不多说,来看看详细的介绍吧
- Django自带的Admin很好用,但是放到生产环境总还差了点什么= =看看admin的介绍:Django奉行Python的内置电池哲学。它
- 1. 调度器scheduler的作用我们都知道,在Go语言中,程序运行的最小单元是gorouines。然而程序的运行最终都是要交给操作系统来
- 说明:这个例子,首先是把SPAN里的内容用display:none;干掉,就是不显示; 然后在A:HOVER时,再把SPAN里的内容disp
- 简介tuple1.元组是以圆括号“()”包围的数据集合,不同成员以“,”分隔。通过下标进行访问2.不可变序列,可以看做不可变的列表,与列表不
- 插件机制是代码/功能反向依赖注入到主体程序的一种方法,编译型语言通过动态加载动态库实现插件。对于Python这样的脚本语言,实现插件机制更简