1 Celery架构,介绍
| |
| |
| |
| -broker:任务中间件,用户提交的任务,存在这个里面(redis,rabbitmq) |
| -worker:任务执行者,消费者,真正执行任务的进程(真正干活的人) |
| -backend:任务结果存储,任务执行后的结果(redis,rabbitmq) |
| |
| |
| |
| -异步任务(区分同步任务) |
| |
| -延迟任务 |
| -定时任务(其他框架做) |
| |
| |
| 注:会有两个服务同时运行,一个是项目服务(django服务),一个是celery服务,项目服务将需要异步处理的任务交给celery服务,celery就会在需要时异步完成项目的需求 |
| |
| 人是一个独立运行的服务(django) | 医院也是一个独立运行的服务(celery) |
| 正常情况下,人可以完成所有健康情况的动作,不需要医院的参与;但当人生病时,就会被医院接收,解决人生病问题 |
| 人生病的处理方案交给医院来解决,所有人不生病时,医院独立运行,人生病时,医院就来解决人生病的需求 |
2 celery的简单使用
2.1 celery_task
| |
| 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.task() |
| def add(a, b): |
| import time |
| time.sleep(2) |
| return a + b |
| |
2.2 提交任务
| |
| import celery_task |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| res = celery_task.add.apply_async(kwargs={'a':2,'b':3}) |
| print(res) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
2.3 查看任务结果
| from celery_task import app |
| |
| from celery.result import AsyncResult |
| |
| id = 'abab1ad3-0e58-4faa-bc05-14d157dc8217' |
| if __name__ == '__main__': |
| a = AsyncResult(id=id, app=app) |
| if a.successful(): |
| print('任务执行成功了') |
| result = a.get() |
| print(result) |
| elif a.failed(): |
| print('任务失败') |
| elif a.status == 'PENDING': |
| print('任务等待中被执行') |
| elif a.status == 'RETRY': |
| print('任务异常后正在重试') |
| elif a.status == 'STARTED': |
| print('任务已经开始被执行') |
| |
3 celery包结构
| |
| -celery_task |
| __init__.py |
| celery.py |
| course_task.py |
| order_task.py |
| user_task.py |
| 提交任务.py |
| 查看结果.py |
3.1 celery_task /celery.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,include=[ |
| 'celery_task.course_task', |
| 'celery_task.order_task', |
| 'celery_task.user_task', |
| ]) |
| |
| |
| |
| |
3.2 celery_task /任务.py
| |
| import time |
| from .celery import app |
| |
| |
| @app.task() |
| def send_sms(phone, code): |
| time.sleep(3) |
| print('短信发送成功,手机号是:%s,验证码是:%s' % (phone, code)) |
| return '短信发送成功' |
| |
| |
| |
| |
| from .celery import app |
| |
| @app.task() |
| def make_order(): |
| with open(r'D:\py18\luffy_api\script\2 celery的包结构\celery_task\order.txt', 'a', encoding='utf-8') as f: |
| f.write('生成一条订单\n') |
| return True |
| |
| |
| |
| |
| from .celery import app |
| @app.task() |
| def add(a,b): |
| return a+b |
| |
3.3 提交任务.py
| from celery_task import user_task,order_task |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| res=user_task.send_sms.delay('12345566677', '8888') |
| print(res) |
3.4 查看结果.py
| from celery_task.celery import app |
| from celery.result import AsyncResult |
| |
| id = '0f283e22-e8d0-40a6-a8ed-8998038bc7a3' |
| if __name__ == '__main__': |
| a = AsyncResult(id=id, app=app) |
| print(app.conf) |
| if a.successful(): |
| print('任务执行成功了') |
| result = a.get() |
| print(result) |
| elif a.failed(): |
| print('任务失败') |
| elif a.status == 'PENDING': |
| print('任务等待中被执行') |
| elif a.status == 'RETRY': |
| print('任务异常后正在重试') |
| elif a.status == 'STARTED': |
| print('任务已经开始被执行') |
4 celery异步任务,延迟任务
4.1 执行延迟任务
| from datetime import datetime, timedelta |
| |
| eta=datetime.utcnow() + timedelta(seconds=50) |
| |
| res=user_task.send_sms.apply_async(args=(200, 50), eta=eta) |
| print(res) |
4.1 执行异步任务
| |
| user_task.send_sms.apply_async(args=('12345566677', '8888')) |
| |
| res=user_task.send_sms.delay('12345566677', '8888') |
5 celery定时任务
5.1 第一步:celey.py中写入
| |
| |
| |
| app.conf.timezone = 'Asia/Shanghai' |
| |
| app.conf.enable_utc = False |
| |
| |
| from datetime import timedelta |
| from celery.schedules import crontab |
| app.conf.beat_schedule = { |
| 'send_sms_every_3_seconds': { |
| 'task': 'celery_task.user_task.send_sms', |
| 'schedule': timedelta(seconds=3), |
| |
| 'args': ('18953675221', '8888'), |
| }, |
| 'make_order_every_5_seconds': { |
| 'task': 'celery_task.order_task.make_order', |
| 'schedule': timedelta(seconds=5), |
| }, |
| 'add_every_1_seconds': { |
| 'task': 'celery_task.course_task.add', |
| 'schedule': crontab(hour=8, day_of_week=1), |
| 'args': (3, 5), |
| }, |
| } |
| |
5.2 第二步:启动worker
| |
| celery worker -A celery_task.main -l info -P eventlet |
| |
5.3 第三步:启动beat
| celery beat -A celery_task -l |
6 django中集成celery
| |
| -django-celery |
| |
| -我们自己使用包结构集成到django中 |
| |
| |
| |
| from celery_task.user_task import send_sms |
| def test(request): |
| mobile = request.GET.get('mobile') |
| code = '9999' |
| res = send_sms.delay(mobile, code) |
| print(res) |
| |
| return HttpResponse(res) |
7 django集成celery实现定时任务(定时更新首页轮播图)
| |
| -因为如果不加缓存,每次用户访问首页,都去查一次数据库,对数据库压力大 |
| -第一次访问查数据库,拿到数据,放到缓存(redis),以后再访问,直接从redis中能够获取 |
| |
| -双写一致性问题(redis缓存和mysql数据不同步) |
| -有方案 |
| -缓存穿透,缓存击穿,缓存雪崩问题(暂时不讲) |
| class BannerView(ViewSetMixin, ListAPIView): |
| queryset = models.Banner.objects.all().filter(is_delete=False, is_show=True).order_by('orders')[ |
| :settings.BANNER_COUNT] |
| serializer_class = serializer.BannerSerializer |
| |
| def list(self, request, *args, **kwargs): |
| |
| |
| |
| banner_list = cache.get('banner_list_cache') |
| if not banner_list: |
| |
| print('查了数据库') |
| res = super().list(request, *args, **kwargs) |
| banner_list = res.data |
| |
| cache.set('banner_list_cache', banner_list) |
| return Response(data=banner_list) |
8 双写一致性问题
| |
| |
| -先更新数据库,再更新缓存(可靠性高一些) |
| -先更新数据库,再删缓存(可靠性高一些) |
| |
| -先删缓存,再更新数据库(缓存删了,数据库还没更新,来了一个请求,缓存了老数据) |
| |
| -定时更新(对实时性要求不高) |
| -每隔12个小时,更新一下缓存 |
| |
8 首页轮播图缓存定时更新
8.1 home_task.py
| |
| |
| from celery_task.celery import app |
| from home import models |
| from django.conf import settings |
| from home import serializer |
| from django.core.cache import cache |
| |
| |
| @app.task() |
| def update_banner(): |
| |
| queryset = models.Banner.objects.all().filter(is_delete=False, is_show=True).order_by('orders')[ |
| :settings.BANNER_COUNT] |
| |
| ser = serializer.BannerSerializer(instance=queryset, many=True) |
| |
| banner_list = ser.data |
| for banner in banner_list: |
| banner['image'] = settings.BACKEND_URL % str(banner['image']) |
| |
| |
| cache.set('banner_list_cache', banner_list) |
| return True |
8.2 celery.py
| from celery import Celery |
| |
| |
| import os |
| os.environ.setdefault("DJANGO_SETTINGS_MODULE", "luffy_api.settings.dev") |
| |
| |
| |
| |
| |
| broker = 'redis://127.0.0.1:6379/1' |
| backend = 'redis://127.0.0.1:6379/2' |
| |
| app = Celery(__name__, backend=backend, broker=broker, include=[ |
| 'celery_task.course_task', |
| 'celery_task.order_task', |
| 'celery_task.user_task', |
| 'celery_task.home_task', |
| ]) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| app.conf.timezone = 'Asia/Shanghai' |
| |
| app.conf.enable_utc = False |
| |
| |
| from datetime import timedelta |
| |
| app.conf.beat_schedule = { |
| 'update_banner_every_3_seconds': { |
| 'task': 'celery_task.home_task.update_banner', |
| 'schedule': timedelta(seconds=3), |
| }, |
| } |
| |
8.3 启动djagno,启动beat,启动worker
| python manage.py runserver |
| celery -A celery_task beat -l info |
| celery -A celery_task worker -l info -P eventlet |
| |
celery定义一个1小时后执行的任务
| from datetime import datetime, timedelta |
| from celery import Celery |
| |
| app = Celery('my_tasks', broker='amqp://guest@localhost//') |
| |
| @app.task |
| def my_task(): |
| |
| pass |
| |
| |
| eta_time = datetime.now() + timedelta(hours=1) |
| |
| |
| result = my_task.apply_async(eta=eta_time) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具