celery异步执行任务
celery介绍和安装
Celery 的作用:
-1 异步任务
-2 定时任务
-3 延迟任务
celery的运行原理:
1)可以不依赖任何服务器,通过自身命令,启动服务
2)celery服务为为其他项目服务提供异步解决任务需求的
注:会有两个服务同时运行,一个是项目服务,一个是celery服务,项目服务将需要异步处理的任务交给celery服务,celery就会在需要时异步完成项目的需求
人是一个独立运行的服务 | 医院也是一个独立运行的服务
正常情况下,人可以完成所有健康情况的动作,不需要医院的参与;但当人生病时,就会被医院接收,解决人生病问题
人生病的处理方案交给医院来解决,所有人不生病时,医院独立运行,人生病时,医院就来解决人生病的需求
celery架构(Broker,backend 都用redis)
- 1 任务中间件 Broker(中间件),其他服务提交的异步任务,放在里面排队
-需要借助于第三方 redis rabbitmq - 2 任务执行单元 worker 真正执行异步任务的进程
-celery提供的 - 3 结果存储 backend 结果存储,函数的返回结果,存到 backend中
-需要借助于第三方:redis,mysql
使用场景 :
异步执行:解决耗时任务
延迟执行:解决延迟任务
定时执行:解决周期(周期)任务
celery快速使用
第一步:安装celery模块
pip install celery
第二步:
在scripts文件夹中 创建 celery_m文件夹
在celery_m文件夹下创建 main.py文件
from celery import Celery
# 提交的异步任务在这里面 指定redis地址和库
broker = 'redis://127.0.0.1:6379/2'
# 完成的结果放在这里面 指定redis地址和库
backend = 'redis://127.0.0.1:6379/3'
app = Celery(main='celery_text', backend=backend, broker=broker)
# 生成一个对象
@app.task
def add(a, b):
import time
time.sleep(3)
return a + b
# 给需要用到异步执行的方法装上装饰器
第三步:
提交异步任务
可以再任意文件中执行
from main import add
把带异步执行的方法导入
# 异步调用
res = add.delay(2,3)
# 放入异步中待执行
print(res)
# 得到一个任务id 已经把这个任务提交到了异步待执行状态
# 9eb94989-ed8a-4d70-a349-658d026aa419
第四步:
开启异步任务执行 所有放在异步中的任务都会执行
在pycharm终端开启 路径要在 celery_m文件夹下
'''执行该命令需要到celery_mk这一级目录'''
执行命令
celery -A celery worker -l info
第五步:
根据待执行任务id 查看结果
# 查看异步提交的结果
from main import app
# 导入我们创建的Celery对象 名叫app
from celery.result import AsyncResult
id = '0af2910f-f8aa-4f70-9c4e-bf09b95c8672'
# 放入异步是就会返回一个id给你, 根据id来查看异步执行的结果
if __name__ == '__main__':
a = AsyncResult(id=id, app=app)
if a.successful():
result = a.get()
print(result)
elif a.failed():
print('任务失败')
elif a.status == 'PENDING':
print('任务等待中被执行')
elif a.status == 'RETRY':
print('任务异常后正在重试')
elif a.status == 'STARTED':
print('任务已经开始被执行')
celery包结构
此包创建在项目跟路径下 与manage同级
mac:celery -A celery_pack worker -l info
win:celery -A celery_pack worker -l info -P eventlet
celery_pack # celery包
├── __init__.py # 包文件
├── celery.py # celery连接和配置相关文件,且名字必须交celery.py
└── tasks.py # 所有任务函数
├── add_task.py # 添加任务
└── get_result.py # 获取结果
执行异步任务/延迟任务
celery.py---创建app
from celery import Celery
import os
broker = 'redis://127.0.0.1:6379/1'
# 设置提交任务到redis的哪个库
backend = 'redis://127.0.0.1:6379/2'
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flow_props_api.settings.dev')
# 管理的django配置文件
# 设置结果存到到redis的哪个库
app = Celery(broker=broker, backend=backend, include=['celery_pack.tasks'])
tasks.py--设置任务
需要异步执行的任务抽取成函数,传递需要的参数
统一存放编写需要用到celery服务的方法
from .celery import app
from order.models import Order
from datetime import datetime
from flow_props_api.apps.user.models import User
@app.task
def create_sell_order(order_pay,props_id,user_id,time_new,action,server,number,price):
print(order_pay,props_id,user_id,time_new,action,server,number,price)
user_obj = User.objects.filter(pk=user_id).first()
if user_obj.alipay == order_pay:
res = str(datetime.now())
order_id = res.replace('-', '').replace(' ', '').replace(':', '').replace('.', '')[0:16]
if props_id == 1:
user_obj.free_level_1 = user_obj.free_level_1 - number
if user_obj.free_level_1 < 0:
return '道具库存不足'
elif props_id == 2:
user_obj.free_level_2 = user_obj.free_level_2 - number
if user_obj.free_level_2 < 0:
return '道具库存不足'
elif props_id == 3:
user_obj.free_level_3 = user_obj.free_level_3 - number
if user_obj.free_level_3 < 0:
return '道具库存不足'
elif props_id == 4:
user_obj.free_level_4 = user_obj.free_level_4 - number
if user_obj.free_level_4 < 0:
return '道具库存不足'
else:
return '道具库存不足'
Order.objects.create(seller_id=user_id, price=price, ordef_id=order_id, action=action, props_id_id=props_id,
number=number, Star=server, create_time=time_new, type_time=time_new,
order_pay=order_pay)
user_obj.save()
return '创建成功'
else:
return '数据错误,提交失败'
add_task.py--提交任务文件可单独放置
导入设置好的任务 通过.delay方法提交到worker中执行
得到一个任务id返回值,可以用此返回值查询异步worker执行好的结果
from celery_pack.tasks import create_sell_order
from celery_pack.celery import app
举例:异步执行创建商品订单操作
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
action = request.data.get('action')
props_id = request.data.get('props_id')
time_new = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
order_pay = request.data.get('order_pay')
user_id = request.data.get('seller_id')
server = request.data.get('Star')
price = request.data.get('price')
number = request.data.get('number')
task_num = create_sell_order.delay(order_pay=order_pay, props_id=props_id,
user_id=user_id, action=action, time_new=time_new, server=server,
price=price, number=number
)
导入异步任务 获得任务的编号
task_num = str(task_num)
return MyResponse(msg='发布中', data=task_num)
'''
设置延迟任务
生成一个时间对象,执行.apply_async方法,需要参数传入 args=(200, 50)中,
eta= 过期时间 配置一个时间对象
'''
# 添加延迟任务
eg:
from datetime import datetime, timedelta
time_obj=datetime.utcnow() + timedelta(seconds=30)
# 生成一个时间对象,延迟30秒执行(timedelta(seconds=30))
任务.apply_async(args=(200, 50), eta=time_obj)
该任务将会在运行后延迟30执行
获取结果函数
from celery.result import AsyncResult
举例:在另一个接口获取接口,配合前端,先发送创建订单请求
获取到创建订单任务id 然后在启动循环任务 待着任务id来查询执行结果
@action(methods=['POST'], detail=False)
def task_result(self, request):
task_id = request.data.get('task_id')
result = AsyncResult(id=task_id, app=app)
if result.successful():
result = result.get()
return MyResponse(msg=result)
elif result.failed():
return MyResponse(code=102, msg='违规操作,联系管理员')
elif result.status == 'PENDING':
return MyResponse(code=101,msg='等待执行中')
执行定时任务
celery.py文件中 ---添加定时任务配置
第一步:
from celery import Celery
broker = 'redis://127.0.0.1:6379/2'
# 设置提交任务到redis的哪个库
backend = 'redis://127.0.0.1:6379/3'
# 设置结果存到到redis的哪个库
app = Celery(broker=broker, backend=backend, include=['celery_pack.tasks'])
# 时区
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False
# 任务的定时配置
from celery.schedules import crontab
app.conf.beat_schedule = {
'task_1': {
'task': 'celery_pack.tasks.bobo',
# 'schedule': timedelta(seconds=3),
# 时间对象 每3秒执行一次
'schedule': crontab(hour=23,minute=58), # 每天晚上23点58分执行
# 'args': (300, 150),
},
'task_2': {
'task': 'celery_pack.tasks.bobobo',
# 需要执行的函数
# 'schedule': timedelta(seconds=3),
# 时间对象 每3秒执行一次
'schedule': crontab(hour=8, day_of_week=1) # 每周一早八点执行
# 'args': (300, 150),
}
}
第二步:
tasks.py中 编写定时任务
from .celery import app
@app.task
def bobo():
print('我执行了')
return '定时任务'
@app.task
def bobobo():
print('我执行了')
return '定时任务'
第三步:
确定开始启动定时任务
切记 要在celery_pack包所在的父级路径下执行
1.启动beat 定时任务需要启动beat
celery -A celery_pack beat -l info
2.启动worker 异步任务只需要启动worker
celery -A celery_pack worker -l info
# 只要任务的代码有改动都需要重启worker
django中使用celery
celery.py中
from celery import Celery
import os
broker = 'redis://127.0.0.1:6379/2'
# 设置提交任务到redis的哪个库
backend = 'redis://127.0.0.1:6379/3'
# 设置结果存到到redis的哪个库
app = Celery(broker=broker, backend=backend, include=['celery_pack.tasks'])
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'LufeiApi.settings.dev')
如果要在django中使用就一定要加这句话
前端代码展示
1. 先发送请求 携带参数 获得let task_id1 = res.data.data 异步任务id号
2.开启循环任务 每2秒带着task_id1请求结果,拿到结果关闭循环任务
if (order == true) {
this.$axios.post(this.$settings.BASE_URL + '/order/order/', {
seller_id: this.user_obj.id,
props_id: this.props_id,
Star: this.server,
order_pay: this.user_obj.alipay,
number: this.number,
price: this.price,
action: '0',
}).then(res => {
if (res.data.code == 100) {
Toast.success(res.data.msg)
let task_id1 = res.data.data
this.t = setInterval(() => {
this.$axios.post(this.$settings.BASE_URL + '/order/order/task_result/', {
task_id: task_id1
}).then(res => {
if (res.data.code == 100) {
clearInterval(this.t)
this.t = null
Toast(res.data.msg)
this.$router.push('/home')
} else {
console.log(res.data.msg)
}
})
}, 2000)
} else {
Toast.fail(res.data.msg)
}
})
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示