在Django中使用celery

283 阅读3分钟

参考的博客

(大江狗)pythondjango.cn/
一些更详细的配置之类的建议从这里查看

安装的包与版本

celery==5.0.5
redis==3.5.3

# 需要设置定时或周期任务时安装
django-celery-beat==2.2.0

# 视情况需要,需要存储任务结果时安装,视情况需要,假如将存储任务结果储存在redis上的话,则不用安装
# 本文将结果存储位置在redis上,不进行安装
django-celery-results==2.0.1

配置项

首先创建了项目,名为forumend,那么需要在forumend/forumend(也就是和settings.py同目录)
目录下 :
添加文件celery.py 并修改init.py文件:

celery.py

import os
from celery import Celery

""" 设置环境变量 
    forumend.settings就是forumend/forumend下的settings.py文件 """
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'forumend.settings')

""" 实例化 """
app = Celery('forumend')

""" namespace='CELERY'作用是允许你在Django配置文件中对Celery进行配置
    但所有Celery配置项必须以CELERY开头,防止冲突 """
app.config_from_object('django.conf:settings', namespace='CELERY')

""" 自动从Django的已注册app中发现任务 """
app.autodiscover_tasks()

init.py

from .celery import app as celery_app
__all__ = ('celery_app',)

另外还要对settings.py进行配置
在总的配置文件setings.py进行配置 ,这里针对celery中的broker存储结果位置进行配置

settings.py

""" 最重要的配置,设置 消息broker 以及 结果存储位置backend ,
    格式为:db://user:password@host:port/dbname
    如果redis安装在本机,使用localhost或127.0.0.1 :端口/数据库号
    如果docker部署的redis,使用redis://redis:6379 
    
    下面将消息存储在redis 0号数据库上,将结果存储在redis 1号数据库上  
    
    本来应该是BROKER_URL,但是由于在celery.py中配置了
        app.config_from_object('django.conf:settings', namespace='CELERY')\
    由于namesapce的作用,配置项前面要加上CELERY_,最终变成 CELERY_BROKER_URL
    """
CELERY_BROKER_URL = "redis://127.0.0.1:6379/0"
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'

""" celery时区设置,建议与Django settings中TIME_ZONE同样时区,防止时差
    Django设置时区需同时设置USE_TZ=True和TIME_ZONE = 'Asia/Shanghai' """
CELERY_TIMEZONE = TIME_ZONE

同时在settigns.py的已有配置上修改:USE_TZ=TrueTIME_ZONE = 'Asia/Shanghai'

执行异步任务

新建一个子应用,名为user

创建任务

在子应用下创建文件tasks.py
tasks.py

from celery import shared_task
import time

""" 
    这里的任务返回数据到时候会返回到reids 1号数据库中
    注意:
         一般在app下面创建的任务,其任务的装饰器一般使用@shared_task
         但是假如任务不在app下面而是在主项目的目录下或其他位置,一般使用@app.task 
"""

@shared_task
def add(x, y):
    time.sleep(2)
    return x + y

创建视图,路由

views.py

from .tasks import add
from celery.result import AsyncResult
import time
class CeleryTest(APIView):
    def get(self,request):
        # 方式一:异步调用该任务,表示为add运行,参数为3,5,既为add(3,5)
        # add.delay(3, 5)
        # return HttpResponse("Celery works")
        
        # 方式二:使用apply_async可以接收更多的参数
        async_task = add.apply_async(args=[3, 5])
        # 获取任务状态和结果
        status = AsyncResult(async_task.task_id).status
        result = AsyncResult(async_task.task_id).result
        
        " 结果分别为:PENDING None,这是因为视图比任务先执行完。状态以及结果都为不确定? "
        print(status) 
        print(result)
        return HttpResponse("Celery works")

user/urls.py

re_path('^cete$',views.CeleryTest.as_view())

运行并查看结果

1.启动项目
python manage.py runserver

2.打开另一个终端运行worker(注意需要提前打开redis数据库)
Celery -A forumend worker -l info -P eventlet(注意这条命令是Windows端的命令)
显示: image.png

3.浏览器打开路由器指定的视图,打开成功后,查看运行worker的终端,可见运行成功,结果为8 image.png

4.在redis查看结果
在redis数据库的0号数据库可以看到消息,2号数据库可以看到结果

有空再写写怎么实现周期任务......