30 celery的基本使用-执行异步任务+延时任务+轮播图的定时更新
一、celery的基本使用
1.下载
pip install celery
2 测试
二、Celery使用
方式一:快速使用
第一步:scripts/t-celery/main.py
####### 第一步:写一个py文件,实例化得到app,编写任务(main.py) from celery import Celery broker='redis://127.0.0.1:6379/1' # 消息中间件 backend='redis://127.0.0.1:6379/2' # 结果存储 app = Celery(__name__,backend=backend,broker=broker) # app对象的名字,把当前文件的名字给它 # 写任务(函数),使用装饰器装饰一下 @app.task def add(a, b): import time time.sleep(2) return a + b
第二步:scripts/t-celery/main.py/add_task.py在其他系统中,提交任务,(导入任务)
from main import add # 同步调用,不叫提交任务 # res=add(3,4) # print(res) # 异步执行,先提交任务,并不执行 res=add.apply_async(args=[3,4]) # add.apply_async(kwds={'a':4,'b':4}) print(res) # 任务id号:ef5c86e0-5efb-4c05-b073-5a872c8a8c28,查结果
第三步:启动worker执行任务
使用命令启动worker # win机器,需要安装 eventlet pip install eventlet 3.x 及以前:celery worker -A main -l info -P eventlet(需要切换到指定文件夹,cd scripts,cd t-celery) 4.x及以后:celery -A main worker -l info -P eventlet # linux执行下面: celery -A main worker -l info
第四步:worker就会从任务中取出任务执行(右键执行)
第五步:查看任务执行结果(result.py)
from main import app from celery.result import AsyncResult id = 'ef5c86e0-5efb-4c05-b073-5a872c8a8c28' if __name__ == '__main__': asy = AsyncResult(id=id, app=app) if asy.successful(): # 顺利执行完了,可以取结果了 res = asy.get() # 任务执行的结果 print(res) elif asy.failed(): print('任务失败') elif asy.status == 'PENDING': print('任务等待中被执行') elif asy.status == 'RETRY': print('任务异常后正在重试') elif asy.status == 'STARTED': print('任务已经开始被执行')
方式二:包管理形式
# 如果 Celery对象:Celery(...) 是放在一个模块下的 # 1)终端切换到该模块所在文件夹位置:scripts # 2)执行启动worker的命令:celery worker -A 模块名 -l info -P eventlet # 注:windows系统需要eventlet支持,Linux与MacOS直接执行:celery worker -A 模块名 -l info # 注:模块名随意 # 如果 Celery对象:Celery(...) 是放在一个包下的 # 1)必须在这个包下建一个celery.py的文件,将Celery(...)产生对象的语句放在该文件中 # 2)执行启动worker的命令:celery worker -A 包名 -l info -P eventlet # 注:windows系统需要eventlet支持,Linux与MacOS直接执行:celery worker -A 模块名 -l info # 注:包名随意
第一步:建立如下格式
celery_task # 包名 __init__.py celery.py # 必须叫这个名字 course_task.py # 一堆任务 home_task.py # 一堆任务 user_task.py # 一堆任务 任务提交-正常不写在这.py 结果查看--正常也不写在这.py
第二步,在celery.py中写入
from celery import Celery broker='redis://127.0.0.1:6379/1' # 消息中间件 backend='redis://127.0.0.1:6379/2' # 结果存储 # include 表示哪些py文件的任务被app管理 app = Celery(__name__,backend=backend,broker=broker,include=['celery_task.course_task','celery_task.home_task','celery_task.user_task'])
第三步:写好多任务
#scripts/celery_task/user_task.py
from .celery import app # 使用相对路径导入 import time @app.task def send_sms(phone,code): print('短信发送成功','手机号为:%s,code为:%s'%(phone,code)) time.sleep(1) return '手机号为:%s,code为:%s'%(phone,code)
#scripts/celery_task/home_task.py
from .celery import app import time @app.task def banner_update(): print("更新图片") time.sleep(1) return True
第四步:启动worker,在包这一层路径 (scripts下)
(luffy) D:\python19\luffy_backend\scripts>celery -A celery_task worker -l info -P eventlet #在包这一层路径下
#celery -A 包名 worker -l info -P eventlet celery -A celery_task worker -l info -P eventlet
第五步:提交任务(什么时候提交都可以)
from celery_task.user_task import send_sms res=send_sms.apply_async(args=['3354325334',5555]) print(res) # 22f638b7-d5cb-41d4-ad08-12d666871436
第六步:结果查看
from celery_task.celery import app from celery.result import AsyncResult id = '22f638b7-d5cb-41d4-ad08-12d666871436' if __name__ == '__main__': asy = AsyncResult(id=id, app=app) if asy.successful(): # 顺利执行完了,可以取结果了 res = asy.get() # 任务执行的结果 print(res) elif asy.failed(): print('任务失败') elif asy.status == 'PENDING': print('任务等待中被执行') elif asy.status == 'RETRY': print('任务异常后正在重试') elif asy.status == 'STARTED': print('任务已经开始被执行')
异步任务
#异步提交任务 # res=send_sms.delay("2222",666) # print(res) #cbe86900-61b8-4a70-82bf-3de0e2c6441a
延时任务
#延时提交任务(隔一分钟) from datetime import datetime,timedelta eta=datetime.utcnow()+timedelta(minutes=1) res=send_sms.apply_async(args=['1852293111',555],eta=eta) print(res) #89f0223e-ec13-4c77-8436-5749cdbc1dc0
# 修改app的配置文件 # 时区 app.conf.timezone = 'Asia/Shanghai' # 是否使用UTC app.conf.enable_utc = False # 任务的定时配置 from datetime import timedelta from celery.schedules import crontab app.conf.beat_schedule = { 'send_sms':{ 'task': 'celery_task.user_task.send_sms', 'schedule': timedelta(seconds=3), # 每隔3s # 'schedule': crontab(hour=8, day_of_week=1), # 每周一早八点 'args': ('12345667', 8888), } }
第二步:启动worker和beat
# 启动两个任务(worker 和 beat)
cd scripts
celery -A celery_task worker -l info -P eventlet
celery -A celery_task beat -l info
添加任务:自动添加任务,所以要启动一个添加任务的服务beat
此时,会每隔3秒发送一次短信
# 轮播图
# 定时更新轮播图缓存
# 加入缓存,会有问题,缓存不一致----》双写一致性
-先删缓存,再写mysql
-先写mysql,删除缓存
-先写mysql,更新缓存
-定时更新
1. 轮播图加缓存(home/views.py)
def list(self, request, *args, **kwargs): # 先去缓存中查数据,如果有,直接返回 res = cache.get('banner_list') if res: #走了缓存 print('走了缓存') return Response(data=res) else: print('没走缓存') # 如果没有,去数据库查,放入缓存 response = super().list(request, *args, **kwargs) cache.set('banner_list', response.data) return response
2. #将celery_task拉到项目下
3.任务(celery_task/home_task.py)
from .celery import app from django.conf import settings from django.core.cache import cache from home.serializer import BannerSerializer from home.models import Banner import time @app.task def banner_update(): #往django的缓存中写入轮波图的数据 queryset=Banner.objects.all().filter(is_delete=False,is_show=True)[:settings.BANNER_COUNT] ser=BannerSerializer(instance=queryset,many=True) for item in ser.data: item['image']='http://127.0.0.1:8000'+item['image'] cache.set('banner_list',ser.data)
4.定时任务的配置celery_back/celery.py
#在脚本中执行djagno
from celery import Celery import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "luffy.settings.dev") broker='redis://127.0.0.1:6379/1' #消息中间件 backend='redis://127.0.0.1:6379/2' #结果存储 #include表示哪些py文件的任务被app管理 app=Celery(__name__,backend=backend,broker=broker,include=['celery_task.course_task','celery_task.home_task','celery_task.user_task']) # 修改app的配置文件 # 时区 app.conf.timezone = 'Asia/Shanghai' # 是否使用UTC app.conf.enable_utc = False # 任务的定时配置 from datetime import timedelta from celery.schedules import crontab app.conf.beat_schedule = { # 'send_sms':{ # 'task': 'celery_task.user_task.send_sms', # 'schedule': timedelta(seconds=3), # 每隔3s # # 'schedule': crontab(hour=8, day_of_week=1), # 每周一早八点 # 'args': ('12345667', 8888), # } 'update_banner':{ 'task': 'celery_task.home_task.banner_update', 'schedule': timedelta(seconds=3), # 每隔3s # 'schedule': crontab(hour=8, day_of_week=1), # 每周一早八点 'args': (), } }
5.# 启动beat,和worker(路径要对)
(luffy) D:\python19\luffy_backend>
celery -A celery_task worker -l info -P eventlet celery -A celery_task beat -l info
django中使用celery
celery.py
""" celery框架django项目工作流程 1)加载django配置环境 2)创建Celery框架对象app,配置broker和backend,得到的app就是worker 3)给worker对应的app添加可处理的任务函数,用include配置给worker的app 4)完成提供的任务的定时配置app.conf.beat_schedule 5)启动celery服务,运行worker,执行任务 6)启动beat服务,运行beat,添加任务 重点:由于采用了django的反射机制,使用celery.py所在的celery_task包必须放置项目的根目录下 """ # 一、加载django配置环境 import os import django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "luffyapi.settings.dev") django.setup() # 二、加载celery配置环境 from celery import Celery # broker broker = 'redis://127.0.0.1:6379/0' # backend backend = 'redis://127.0.0.1:6379/1' # worker app = Celery(broker=broker, backend=backend, include=['celery_task.tasks']) # 时区 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=10), 'args': (), } }
home_task.py
from .celery import app from django.core.cache import cache from home import models, serializers from django.conf import settings @app.task 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
# 集成到django中
-django服务和celery服务独立运行的
-可能task的任务会放在app中,只要正常操作:task的py文件在app中注册,正常提交,都会正常执行