Python—在Django中使用Celery

一.Django中的请求

  Django Web中从一个http请求发起,到获得响应返回html页面的流程大致如下:

    http请求发起 

    经过中间件

      http handling(request解析) 

    url mapping(url匹配找到对应的View) 

    在View中进行逻辑(包括调用Model类进行数据库的增删改查)

    经过中间件

    返回对应的template/response。

  

  同步请求:所有逻辑处理、数据计算任务在View中处理完毕后返回response。在View处理任务时用户处于等待状态,直到页面返回结果。

  异步请求:View中先返回response,再在后台处理任务。用户无需等待,可以继续浏览网站。当任务处理完成时,我们可以再告知用户。

二.Django中使用Celery

安装

pip3 install django-celery

配置

  首先创建一个django项目,结构如下:

                

 

 

    之后再settings.py的同级目录添加celeryconfig.py配置文件,更多配置信息可以参考官方文档。

import djcelery
from datetime import timedelta

djcelery.setup_loader()

# 导入任务
CELERY_IMPORTS = [
    'celeryapp.tasks'
]
# 设置队列
CELERY_QUEUES = {
    'beat_tasks': {
        'exchange': 'beat_tasks',
        'exchange_type': 'direct',
        'binding_key': 'beat_tasks'
    },
    'work_queue': {
        'exchange': 'work_queue',
        'exchange_type': 'direct',
        'binding_key': 'work_queue'
    }
}
# 设置默认列队,不符合其他队列的任务放在默认队列
CELERY_DEFAULT_QUEUE = 'work_queue'

# 有些情况下可以防止死锁
CELERYD_FORCE_EXECV = True

# 设置并发数量
CELERYD_CONCURRENCY = 4

# 每个worker最多执行100个任务,防止泄露内存
CELERYD_MAX_TASKS_PER_CHILD = 100

# 单个任务最多执行时间
CELERYD_TASK_TIME_LIMIT = 12 * 30

# 设置定时执行
CELERYBAET_SCHEDULE = {
    'task1': {
        'task': 'course-task',
        'schedule': timedelta(seconds=5),
        'options': {
            'queue': 'beat_tasks'
        }
    }
}

CELERY_ACCEPT_CONTENT = ['pickle', 'json', ]

BROKER_BACKEND = 'redis'
BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/2'
celeryconfig.py
from .celeryconfig import *  # 导入Celery配置信息


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'celeryapp.apps.CeleryappConfig',
    'djcelery'  # 注册celery
]
settings.py
import time
from celery.task import Task


class Course(Task):
    name = 'course-task'

    def run(self, *args, **kwargs):
        print('start...')
        time.sleep(3)
        print(f'args={args},kwargs={kwargs}')
        print('end task....')
tasks.py
from django.http import JsonResponse
from celeryapp.tasks import Course


def course(request, *args, **kwargs):
    # 执行异步任务
    print("start course...")
    # Course.delay()
    # 可以使用apply_async传递参数,指定队列
    Course.apply_async(args=('hello',), queue='work_queue')
    print("end course...")
    return JsonResponse({'result': 'ok'})
views.py
from django.contrib import admin
from django.urls import path
from celeryapp.views import course

urlpatterns = [
    path('admin/', admin.site.urls),
    path('course/', course),
]
urls.py

启动redis作为消息中间人

redis-server 

启动django项目,然后访问http://localhost:8000/course/,触发任务

python manage.py runserver

启动worker

python manage.py celery worker -l info   

    可以看到配置情况,以及任务的执行情况:

            

 

 

      

 

 

      

 

 

 启动beat

python manage.py celery beat -l info

         

 

 

 三.常见错误

♦  AttributeError: ‘str’ object has no attribute ‘items’

解决方法: redis版本过高,降低redis版本即可

pip install redis==2.10.6

 

♦  from kombu.async.timer import Entry, Timer as Schedule, to_timestamp, logger SyntaxError: invalid syntax

  这个是python3.7目前不支持kombu,降低python版本至3.6即可,可以使用conda进行直接安装

conda install python=3.6.8

 四.过程监控

  Celery提供了一个工具flower,将各个任务的执行情况、各个worker的健康状态进行监控并以可视化的方式展现。

安装监控

pip install flower

执行flower

python manage.py celery flower

本地端口:5555查看监控

刷新course页面,查看tasks,发现有刚刚执行完成的任务

  查看broker

 

 进入Monitor查看任务执行情况,执行成功,执行失败,消耗的时间,队列里面的任务情况

点击的worker查看具体worker情况 

 可以给flower添加密码认证,添加之后再访问则需要输入用户名和密码

python manage.py celery flower --basic_auth=username:password 

 

posted @ 2019-09-16 16:49  ZivLi  阅读(3417)  评论(0编辑  收藏