Django使用celery小記
基礎環境
python 3.7
amqp 2.6.0
celery 4.4.3
Django 2.2
flower 0.9.4
可選使用djcelery,這裏我使用的原生celery
celery簡介及應用場景
Celery是基於Python開發的一個分佈式任務隊列框架,採用生產者-消費者模式,主要由三部分組成:broker(消息隊列)、workers(消費者:處理任務)、backend(存儲結果)
主要應用場景:
1、異步任務(async task) 針對請求執行的任務時間較長的情況
2、定時任務(crontab)
1.用戶發起請求接口
2.接口將任務發送到broker隊列
3.celery worker 監控 broker隊列任務並處理
4.celery worker 將結果存儲到backend
從圖上可以看出Celery包含幾個模塊:
任務模塊 Task (生產者)
包括異步任務和定時任務,異步任務通常在業務邏輯中被觸發併發送到任務隊列中,而定時任務是由Celery Beat進程週期性的將任務發往任務隊列。
消息中間件 Broker (中間人)
Broker就是任務調度隊列,接受任務生產者發送來的消息,將任務存入隊列,之所以需要中間人的原因是Celrey本身是不提供消息隊列的服務,所以需要第三方組件實現,常用的有RabbitMQ、Redis。
任務執行單元Worker (消費者)
Worker是執行任務的單元,它實時監控消息隊列,如果有任務就獲取任務並執行它。
任務存儲Backend(存儲結果)
Backend用於存儲任務的執行結果,存儲可以使用RabbitMQ或者Redis或者數據庫等。
異步任務
目錄結構
mysite/mysite是項目配置
mysite/ola_utils是新建的app
mysite
├── README.MD
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── __pycache__
│ ├── celery.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── ola_utils
├── __init__.py
├── __pycache__
├── admin.py
├── apps.py
├── migrations
├── models.py
├── tasks.py
├── tests.py
└── views.py
celery主配置文件
'''
mysite/mysite/celery.py
'''
# -*- coding: utf-8 -*-
# @Time : 2020/6/8 5:03 PM
# @Author : zhangzd
# @Email : [email protected]
# @File : celery.py
# @Software: PyCharm
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', 'mysite.settings')
app = Celery('mysite', backend='amqp', broker='amqp://guest:guest@localhost:5672')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - 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()
# 允許root 用戶運行celery
platforms.C_FORCE_ROOT = True
# 防止內存泄漏,限制worker執行任務次數
app.conf.worker_max_tasks_per_child = 40
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
# 定時任務
from celery.schedules import crontab
app.conf.update(
CELERYBEAT_SCHEDULE={
'send-report': {
# 具體需要執行的函數
# 該函數必須要使用@shared_task裝飾
'task': 'ola_utils.tasks.report',
# 定時時間
# 每分鐘執行一次,不能爲小數
'schedule': crontab(minute='*/1'),
# 或者這麼寫,每小時執行一次
# "schedule": crontab(minute=0, hour="*/1")
# 執行的函數需要的參數
'args': ()
}
}
)
在mysite/init.py文件中增加如下內容,確保django啓動的時候這個app能夠被加載到
'''
mysite/mysite/__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',)
注意tasks.py必須建在各app的根目錄下,且只能叫tasks.py,不能隨意命名
'''
mysite/ola_utils/tasks.py
'''
from __future__ import absolute_import, unicode_literals
from celery import shared_task
import time
@shared_task
def add(x, y):
time.sleep(10)
return x + y
在視圖文件內調用視圖函數觸發異步任務
'''
mysite/ola_utils/views.py
'''
from django.shortcuts import render
# Create your views here.
import time
from django.http import HttpResponse
from ola_utils.tasks import add
def heartbeat(request):
t = time.time()
try:
# r = test.delay()
r = add.delay(2,6)
print(r)
except Exception as e:
print(e)
return HttpResponse(t)
啓動celery worker
celery -A mysite worker -l info
定時任務
# 定時任務配置
from celery.schedules import crontab
app.conf.update(
CELERYBEAT_SCHEDULE={
'send-report': {
# 具體需要執行的函數
# 該函數必須要使用@shared_task裝飾
'task': 'ola_utils.tasks.report',
# 定時時間
# 每分鐘執行一次,不能爲小數
'schedule': crontab(minute='*/1'),
# 或者這麼寫,每小時執行一次
# "schedule": crontab(minute=0, hour="*/1")
# 執行的函數需要的參數
'args': ()
}
}
)
'''
mysite/ola_utils/tasks.py
'''
@shared_task
def report():
print(5)
return 5
同時執行異步任務和定時任務
celery -B -A mysite worker -l info
結果
其他
celery 官網:https://docs.celeryproject.org/en/4.4.3/django/first-steps-with-django.html
celery 配置參數
https://docs.celeryproject.org/en/master/userguide/configuration.html?highlight=CELERYD_MAX_TASKS_PER_CHILD#std:setting-worker_max_tasks_per_child