参考文档:http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html
中文参考文档:https://www.celerycn.io/ru-men/celery-chu-ci-shi-yong
Celery是一个强大的分布式任务队列,他可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。通常用来实现异步任务和定时任务。异步任务比如发送邮件,文件上传图像处理等;定时任务就是需要在特定时间执行的任务。
任务队列一般用于线程或计算机之间分配工作的一种机制。
任务队列的输入是一个称为任务的工作单元,有专门的工作进行不断的监视任务队列,进行执行新的任务工作。
Celery 通过消息机制进行通信,通常使用中间人(Broker)作为客户端和职程(Worker)调节。启动一个任务,客户端向消息队列发送一条消息,然后中间人(Broker)将消息传递给一个职程(Worker),最后由职程(Worker)进行执行中间人(Broker)分配的任务。
在Windows下安装如下环境:
celery==4.3.0
Django==2.1.8
django-redis==4.10.0
redis==3.3.8
eventlet==0.25.1
PyMySQL==0.9.3
用Redis当Broker: app.conf.broker_url = 'redis://localhost:6379/0'
用Redis当Backend: app.conf.result_backend = 'redis://127.0.0.1:6379/1'
如果redis有设置登录密码:则格式如下:
‘redis://:password@hostname:port/db_number’
在Django中创建一个项目名为testcelery的项目。
testcelery/__init__.py
from __future__ import absolute_import, unicode_literals
import pymysql
pymysql.install_as_MySQLdb()
# 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',)
testcelery/celery.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testcelery.settings')
app = Celery('testcelery')
app.conf.broker_url = 'redis://127.0.0.1:6379/0'
app.conf.result_backend = 'redis://127.0.0.1:6379/1'
# 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()
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
app/tasks.py
from __future__ import absolute_import, unicode_literals
# from celery import app
from uuid import uuid4
from app.models import Result
from testcelery.celery import app
@app.task
def add(x, y):
# 处理完毕存数据库
Result.objects.create(
uuid=uuid4().hex,
result=x+y
)
return x + y
@app.task
def mul(x, y):
return x * y
@app.task
def xsum(numbers):
return sum(numbers)
默认的并发数为当前计算机的 CPU 数
测试
1、本步骤非必须,只是为了测试看可否正常使用redis。
进入django的后台命令模式:
python manage.py shell
逐条输入以下命令:
>>> from django.core.cache import cache
>>> cache.set('a', '444')
True
>>> cache.has_key('a')
True
>>> cache.get('a')
'444'
2、进入django的后台命令模式:
python manage.py shell
>>> from app.tasks import *
>>> add(1, 3)
4
测试异步
>>> res = add.delay(2, 3)
>>> res.status
'PENDING'
此时返回的结果是“PENDING”,应为没有启动Celery
打开另一个终端,如果是Windows输入下面的命令启动Celery:
celery -A testcelery worker --loglevel=info -P eventlet
如果不是Windows则,输入:
celery -A testcelery worker --loglevel=info
启动界面如下:
-------------- celery@PC-201401010008 v4.3.0 (rhubarb)
---- **** -----
--- * *** * -- Windows-7-6.1.7601-SP1 2019-09-08 23:09:22
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: testcelery:0x34b95d0
- ** ---------- .> transport: redis://127.0.0.1:6379/0
- ** ---------- .> results: redis://127.0.0.1:6379/1
- *** --- * --- .> concurrency: 4 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. app.tasks.add
. app.tasks.mul
. app.tasks.xsum
. testcelery.celery.debug_task
[2019-09-08 23:09:23,016: INFO/MainProcess] Connected to redis://127.0.0.1:6379/0
[2019-09-08 23:09:23,028: INFO/MainProcess] mingle: searching for neighbors
[2019-09-08 23:09:24,053: INFO/MainProcess] mingle: all alone
[2019-09-08 23:09:24,060: WARNING/MainProcess] h:\env\dj218\lib\site-packages\celery\fixups\django.py:202: UserWarning: Using settings.DEBUG leads to a memory leak, nev
er use this setting in production environments!
warnings.warn('Using settings.DEBUG leads to a memory leak, never '
此时
>>> res.status
'SUCCESS'
>>> res.result
5
定时任务
配置文件中配置定时任务:
在celery.py 文件中配置:
app.conf.beat_schedule = {
'add-every-30-seconds': {
'task': 'app.tasks.add',
'schedule': 2, # 每2秒执行一次
'args': (3, 4)
},
}
启动Celery的worker
celery -A testcelery worker -l info -P eventlet
再启动定时任务:
celery -A testcelery beat
注意:文件名为celery.py 和导入包名from celery import Celery
有冲突,则需要把celery.py
文件名更改。
涉及两个个地方:
1、项目文件下的__init__.py
文件里
from .celeryconfig import app as celery_app
2、tasks.py
文件里:
from 项目名.celeryconfig import app
任务失败重试
4.0 版本的新功能
@app.task(autoretry_for=(ReadTimeout,), retry_kwargs={'max_retries': 3, 'countdown': 5})
def test_func():
viewutils.test_func()
@app.task
装饰器中的参数:
autoretry_for:
异常类的列表或元组,如果任务在执行的过程中引发异常,任务将自动重试。默认情况下不会自动重试任何异常。
retry_kwargs:
字典类型,自定义配置自动重试参数。注意,如果使用下面的 exponential backoff 选项,countdown 任务选项将由 Celery 的自动重试系统决定,字典中包含 countdown 会被忽略。
retry_backoff:
一个布尔值或一个数字。如果将此选项设置为True,则自动重试将按照 exponential backoff 规则延迟。第一次重试延迟 1 秒,第二次重试延迟 2 秒,第三次延迟 4 秒,第四次延迟 8 秒,以此类推。(如果启用了 retry_jitter 会修改延迟值)。如果该选项设置为数字,则作为延迟因子,例如,该选项设置为 3,那么第一次重试将延迟 3 秒,第二次将延迟 6 秒,第三次延迟 12 秒,第四次延迟 24秒,以此类推。默认情况下,该选项设置为 False,自动重试不会延迟。
retry_backoff_max:
一个数字,如果启动了 retry_backoff,该选项在任务自动重试之间设置以秒为单位的最大延迟。默认情况,该选项默认值为 600,即 10分钟。
autoretry_for
exc:指定抛出的异常
throw:重试时是否通知worker是重试任务
eta:指定重试的时间/日期
countdown:在多久之后重试(每多少秒重试一次)
max_retries:最大重试次数