Celery异步
官网 https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html
-------------- celery@DESKTOP-6RC5C0D v5.2.3 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.19044-SP0 2022-04-01 15:34:29
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: meiduo:0x22dbfe08e50 # 创建的对象名字,地址,
- ** ---------- .> transport: redis://:**@192.168.10.128:6379/8 # 中间人,容器,地址
- ** ---------- .> results: disabled:// # 结果
*** --- * --- .> concurrency: 4 prefork # 进程数量
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
-------------- [queues] # 队列列表
[tasks]
. send_sms_code 任务队列
基本使用
安装
celery 安装
pip install —U Celery
windows 安装
pip install eventlet
基本配置
结构目录
celery文件夹 与 manage.py 同级

main.py主文件
1. 在项目文件上一级创建celert_tasks文件
2. 在目录里面创建main.py文件夹
mian.py
from celery import Celery # 类里面
# 创建实例
celery_app = Celery('meiduo') # 标识 生产者
# 加载配置 容器在什么地方 config
celery_app.config_from_object('celery_tasks.config')
# 注册任务
celery_app.autodiscover_tasks(['celery_tasks.sms']) # 注意::::是 列表
# 配置定时任务
celery_app.conf.timezone = 'Asia/Shanghai' # 时区
celery_app.conf.enable_utc = False # 是否使用UTC
celery_app.conf.beat_schedule = { # 配置beat
# 名字命名
'add-every-10-seconds':{
# 执行task下的 test_email函数
'task':'test_email',
# 每6秒执行一次
# 'schedult': 6,
# 每隔1分钟执行一次
# schedule: crontab(minute="*/1")
# 每6秒一次(时差=6s) 更丰富跟灵活
'schedule':timedelta(seconds=6),
# 传参
'args':('张三',)
}
}
config.py 配置文件
# celery 的配置文件
# 指定中间人、 消息队列、 任务队列、容器 、redis
# redis
result_backend = 'redis://:Ww550076@42.193.152.252:6379/4' # (存储结果)
# redis
broker_url='redis://:123456@192.168.10.128:6379/8' # 数据库消息中间件
# rbmq
broker_url = 'amqp://%s:%s@42.193.152.252:5672/blog' % ('admin', 'chenhaifeng1124') # 林的服务器 (储存任务)
创建工作目录文件夹
tasks文件夹
- 任务.py
- init.py
from celery_tasks.sms.ronglian_sms_sdk.SendMessage import CCP
from celery_tasks.main import celery_app
# 使用装饰器异步任务,保证celery识别任务 celery 提供的装饰器
@celery_app.task(name='send_sms_code') # 起别名
def send_sms_code(mobile,sms_code):
'''发送短信验证码的异步任务'''
'''
mobile:手机号
sms_code:短信验证码
:return: 成功:0 失败:-1
'''
send_ret = CCP().send_template_sms('1', mobile, (sms_code, '5'))
return send_ret
widows运行命令服务器celery
celery -A celery_tasks.main worker -l info -P eventlet 启动服务器
celery -A celery_tasks.main beat # 读取amin里的beat配置(定时任务)
python调用使用
执行异步任务
# 执行异步任务
from celery_tasks.email.tasks import send_verify_email # 导入celery里自定义的函数
import datetime
from celery_tasks.test.tasks import test_sms, test_email
#from celery_tasks.text_main import cel
#from celery.result import AsyncResult
# 执行异步任务 (使用函数.dealy("参数")格式调用)
# result = send_email.delay('陈海峰')
# print(result.id) # 返回的id
#
# result = send_sms.delay('欧子君')
# print(result)
执行定时任务
方式1
在消费者中apply_async传参eta时间
# 执行定时任务
from celery_tasks.email.tasks import send_verify_email # 导入celery里自定义的函数
# 转换当前时间为utc标准
ctime = datetime.datetime.now()
# 转换成国标日期对象
utc_ctime = datetime.datetime.utcfromtimestamp(ctime.timestamp())
# 设置10秒
time_delay = timedelta(seconds=10)
# 添加当前时间+10秒
task_time = utc_ctime + time_delay
# 执行apply_async方法(与delay基本一直,就是能接收更多参数)
result = test_email.apply_async(['911',],eta=task_time)
print(result.id)
django视图中使用案例
# 转换当前时间为utc标准
def get(self, request):
ctime = datetime.datetime.now()
# 转换成国标日期对象
utc_ctime = datetime.datetime.utcfromtimestamp(ctime.timestamp())
# 设置10秒
time_delay = datetime.timedelta(seconds=10)
# 添加当前时间+10秒
task_time = utc_ctime + time_delay
print(task_time)
# 定时任务celery
result = test_celery.apply_async(['chenhaifeng',], eta=task_time)
print(result.id)
time.sleep(1)
asy_res = celery_result(res_id=result.id, res_app=test_celery)
print(asy_res)
return JsonResponse(asy_res)
方式2
生产者配置的beat(定时任务)
celery -A celery_tasks.main worker -l info -P eventlet 启动服务器
# 并发量
-c 10
# 执行读取celery 配置文件 baet(配置的定时任务)
PS D:\Django_mark\New_blogger\new_blog> celery -A celery_task.main beat
# 终端打印值
celery beat v5.2.0 (dawn-chorus) is starting.
__ - ... __ - _
LocalTime -> 2022-11-15 12:25:19
Configuration ->
. broker -> amqp://admin:**@42.193.152.252:5672/blog
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%WARNING
. maxinterval -> 5.00 minutes (300s)
获取异步结果
from celery.result import AsyncResult
from celery_task.main import celery_app
# 获取异步结果
async_result = AsyncResult(id='b065a154-b0e6-4b5b-848e-4de728295b91',app=cel)
def celery_result(res_id, res_app):
# res_id为结果id, res_app为执行的任务函数
async_result = AsyncResult(id=res_id, app=res_app)
res = {
'code': 400,
'res': '执行失败',
'status': '执行失败',
}
if async_result.successful():
# 获取结果
result = async_result.get()
print(result)
res['code'] = 0
res['res'] = result
res['status'] = '执行成功'
# res,forget() # 将结果删除,执行完成,结果不会删除
# async.revoke(terminate=true) # 无论显示是什么时候都要终止
# async,revoke(terminate=false) # 如果任务还没开始执行, 那么就可以终止
elif async_result.failed():
print('执行失败')
elif async_result.status == 'PENDING':
res['code'] = 0
res['res'] = async_result.status
res['status'] = '任务等待'
print('任务等待')
elif async_result.status == 'RETRY':
res['code'] = 0
res['res'] = async_result.status
res['status'] = '任务异常,正在重试'
print('任务异常,正在重试')
elif async_result.status == 'STARTED':
res['code'] = 0
res['res'] = async_result.status
res['status'] = '任务已经开始被执行'
print('任务已经开始被执行')
return res

Django完整案例
结构
- (项目根目录创建文件夹celery_task)
D:celery_task
│ config.py
│ main.py
│ result_celery.py
│
├─email
│ │ tasks.py
│ │ __init__.py
│ │
│ └─__pycache__
│ tasks.cpython-311.pyc
│ __init__.cpython-311.pyc
│
└─__pycache__
config.cpython-311.pyc
main.cpython-311.pyc
result_celery.cpython-311.pyc
main.py
from celery import Celery
from datetime import timedelta
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "o_project.settings")
celery_app = Celery('diary')
celery_app.config_from_object('celery_task.config')
celery_app.autodiscover_tasks(['celery_task.email'])
celery_app.conf.beat_schedule = { # 配置beat
'add-every-10-seconds':{
# 执行task下的 test_email函数
'task':'send_sms_code',
# 每6秒执行一次
# 'schedult': 6,
# 每隔1分钟执行一次
# schedule: crontab(minute="*/1")
# 每6秒一次(时差=6s) 更丰富跟灵活
'schedule':timedelta(seconds=6),
# 传参
'args':(17666292938,1)
}
}
config.py
- amqp任务队列
- mongodb存储结果
# result_backend = "" # 储存结果
broker_url = "amqp://%s:%s@42.193.152.252:5672/blog" % ('admin', 'chenhaifeng1124') # 储存任务
result_backend = 'mongodb://%s:%s@192.168.50.225:27017/' % ('test', '123456')
mongodb_backend_settings = {
'database': 'diary',
'taskmeta_collection': 'diary_celery_collection',
}
result_celery.py
- 查询结果
from celery.result import AsyncResult
# 获取异步结果
# async_result = AsyncResult(id='b065a154-b0e6-4b5b-848e-4de728295b91',app=cel)
def celery_result(res_id, res_app):
async_result = AsyncResult(id=res_id, app=res_app)
res = {
'code': 400,
'res': '执行失败',
'status': '执行失败',
}
if async_result.successful():
# 获取结果
result = async_result.get()
print(result)
res['code'] = 0
res['res'] = result
res['status'] = '执行成功'
# res,forget() # 将结果删除,执行完成,结果不会删除
# async.revoke(terminate=true) # 无论显示是什么时候都要终止
# async,revoke(terminate=false) # 如果任务还没开始执行, 那么就可以终止
print('执行成功')
elif async_result.failed():
print('执行失败')
elif async_result.status == 'PENDING':
res['code'] = 0
res['res'] = async_result.status
res['status'] = '任务等待'
print('任务等待')
elif async_result.status == 'RETRY':
res['code'] = 0
res['res'] = async_result.status
res['status'] = '任务异常,正在重试'
print('任务异常,正在重试')
elif async_result.status == 'STARTED':
res['code'] = 0
res['res'] = async_result.status
res['status'] = '任务已经开始被执行'
print('任务已经开始被执行')
return res
创建任务
- celery_task/email文件夹
- 文件夹下创建tasks.py文件
- 文件夹下创建__init__.py文件
from celery_task.main import celery_app
# 使用装饰器异步任务,保证celery识别任务 celery 提供的装饰器
@celery_app.task(name='send_sms_code') # 起别名
def send_sms_code(mobile,sms_code):
'''发送短信验证码的异步任务'''
'''
mobile:手机号
sms_code:短信验证码
:return: 成功:0 失败:-1
'''
print(f'执行异步任务send_sms_code{mobile}, {sms_code}')
return mobile, sms_code
终端中测试调用任务
- 开启celery
celery -A celery_task.main worker -l info -P eventlet
- 测试任务delay
python manage.py shell
>>> from celery_task.email.tasks import send_sms_code
>>> from celery_task.result_celery import celery_result
>>> send_sms_code.delay(13113003318,1) # 运行
>>> res = celery_result('30054694-b865-47dd-bd83-7a1973f29541', send_sms_code) # 获取储存结果
>>> res
{'code': 0, 'res': [13113003318, 1], 'status': '执行成功'}