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('任务已经开始被执行')

 

三、执行异步任务和延迟任务(任务提交,正常不写这里.py)

异步任务

#异步提交任务
# 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

 

 

四、执行定时任务

第一步: 在celery.py中加入

# 修改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中注册,正常提交,都会正常执行

posted @ 2022-02-28 19:27  甜甜de微笑  阅读(608)  评论(0编辑  收藏  举报