异步框架celery的使用以及秒杀任务逻辑
celery框架
celery做异步和延迟任务基本使用
1.安装pip install celery
2.实例化得到对象
from celery import Celery
broker='redis://127.0.0.1:6379/1' # 消息中间件
backend='redis:127.0.0.1:6379/2' # 结果储存
app=Celery('任务名',broker=broker,backend=backend)
3.将一个任务变成celery能提交的任务
@app.task
def add(a,b)
return a+b
4.提交任务将文件内的文件导入过来
from main import add
res=add.delay(4,5) # 执行一次将任务提交到消息中间件中
res=add.apply_async(args=[参数],eta=时间对象) #到点触发
res=add.apply_async(args=[参数],coundown=10) #单位为秒,就是十秒后执行
参数retry:True就是默认任务失败后重试
5.使用celery命令执行任务,就是启动工作区worker
执行命令在生成app对象的文件夹路径执行
# win上:装eventlet
celery -A main worker -l info -P eventlet # main对应的是生成py文件所对应的py文件
# linux、mac上
celery -A main worker -l info
6.可以在我们设置的broker和backend中的库查看任务和结果
celery在django中做定时任务的使用
根路径建包celery_task
celery.py
# 一、加载django配置环境
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "luffyapi.settings.dev")
# 二、加载celery配置环境
from celery import Celery
# broker
broker = 'redis://localhost:6379/0'
# backend
backend = 'redis://localhost:6379/1'
# worker
app = Celery(broker=broker, backend=backend, include=['celery_task.tasks'])# include内放了多个任务的绝对路径,任务也可以放在django中
# 时区
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False
# 任务的定时配置
from datetime import timedelta
from celery.schedules import crontab
app.conf.beat_schedule = {
'update-banner-list': {
'task': 'celery_task.tasks.update_banner_list', # 任务所在路径
'schedule': timedelta(seconds=3), # 定时多久做一次
'args': (), # 指定参数直接传吗,有参可以通过redis作为中间件拿
}
}
task.py
from .celery import app
from django.core.cache import cache
from home import models, serializers
from django.conf import settings
@app.task # 表示是可以被celery提交的任务
def update_banner_list():
queryset = models.Banner.objects.filter(is_delete=False, is_show=True).order_by('orders')[:settings.BANNER_COUNT]
banner_list = serializers.BannerSerializer(queryset, many=True).data
# 拿不到request对象,所以头像的连接base_url要自己组装
for banner in banner_list:
banner['image'] = 'http://127.0.0.1:8000%s' % banner['image']
cache.set('banner_list', banner_list, 86400)
return True
启动命令在终端
1.启动worker就是执行任务
celery -A celery_task worker -l info -P eventlet
2.启动beat就是向队列中提交任务
celery -A celery_task beat -l info
# 需要开两个终端
使用celery做秒杀任务
1.前端通过按钮向后端发送请求
2.后端是直接将这个任务加入消息队列中,采用异步的方法,不返回结果,将任务id返回
3.前端起一个定时访问通过任务id的请求问后端是否出结果
4.后端:
def get(self, resquest):
task_id = resquest.GET.get('task_id')
from celery_task.celery import app
from celery.result import AsyncResult
asy = AsyncResult(id=task_id, app=app)
if asy.successful():
result = asy.get()
return APIResponse(msg='秒杀成功')
elif asy.failed():
return APIResponse(msg='秒杀失败')
else:
return APIResponse(msg='请继续等待')
双写一致性的问题
# 对于查询之后将数据存在redis中,后面访问都是又都是由redis提供数据,当数据库更新时,redis没有更新,所以存在了数据库与redis数据不一致的情况
解决方案:
1.先更新数据库,再更新缓存 # 会出现在更新了的时候还没更新缓存就是
2.先删除缓存,再更新数据库 # 删除之后可能数据还没来得及更新,就又进行了请求数据,又存在了缓存中
3.先更新数据库,再删除缓存 # 推荐业内常用
4.定时更新缓存 # 推荐
浙公网安备 33010602011771号