码迷,mamicode.com
首页 > 其他好文 > 详细

celery

时间:2021-01-12 10:36:03      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:back   中文   bsp   include   push   返回结果   return   port   反射   

Celery 官网:http://www.celeryproject.org/

Celery 官方文档英文版:http://docs.celeryproject.org/en/latest/index.html

Celery 官方文档中文版:http://docs.jinkan.org/docs/celery/

Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统

专注于实时处理的异步任务队列

同时也支持任务调度

1 celery架构

# 1. 消息中间件(message broker)
    Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis等等
    
# 2. 任务执行单元(worker)和 
    Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。

# 3. 任务执行结果存储(task result store)组成。
    Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis等

技术图片

 

 2 使用场景

异步执行:解决耗时任务,将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等

延迟执行:解决延迟任务

定时执行:解决周期(周期)任务,比如每天数据统计

 

3 两种celery任务结构

1 如果 Celery对象:Celery(...) 是放在一个模块下的

1)终端切换到该模块所在文件夹位置:scripts
2)执行启动worker的命令:celery worker -A 模块名 -l info -P eventlet
    注意: 
    1. windows系统需要eventlet支持: pip insall eventlet
    2. Linux与MacOS直接执行:celery worker -A 模块名 -l info
    3.模块名一定要叫celery.py

2 如果 Celery对象:Celery(...) 是放在一个包下的

1)必须在这个包下建一个celery.py的文件,将Celery(...)产生对象的语句放在该文件中
2)执行启动worker的命令:celery worker -A 包名 -l info -P eventlet
    注意: 
    1. windows系统需要eventlet支持: pip insall eventlet
    2. Linux与MacOS直接执行:celery worker -A 模块名 -l info
    3. 模块名一定要叫celery.py

 

4 celery执行异步任务

1 模块结构

技术图片

 

 

celery_task/celery_app.py

from celery import Celery

broker = redis://127.0.0.1:6379/1
backend = redis://127.0.0.1:6379/2

# include=[被管理的任务文件路径, ]
app = Celery(__name__, broker=broker, backend=backend, include=(celery_task, ))

# 放在模块下的启动celery命令
‘‘‘
windows中: 
    celery worker -A 模块名 -l info -P eventlet
linux中: 
    clery worker -A 模块名 -l info

-A: 表示被执行的模块路径. 如果是相对, 那么就需要cd到该模块下执行.
-l: 表示展示日志    
‘‘‘

celery_task/celery_task.py

from celery_app import app


@app.task  # 添加任务
def add(x, y):
    print(x + y:, x + y)
    return x + y

 celery_task/excute_task.py

import utils
from celery_task import add


# 往broker中添加一个任务.
‘‘‘
只要是worker一直是在启动的状态, 一旦往broker中添加了任务. 
那么这个任务就会立刻被worker执行, 执行的结果存储到backend中
‘‘‘
task_uuid = add.delay(1, 2)
# 注意: task_uuid是一个AsyncResult对象. 因此需要str才能保存到reids中
‘‘‘
redis.exceptions.DataError: Invalid input of type: ‘AsyncResult‘. Convert to a bytes, string, int or float first.
‘‘‘
# utils.conn.rpush(‘task_id‘, task_uuid)  # 错误
utils.conn.rpush(task_id, str(task_uuid))

 celery_task/get_result.py

from celery.result import AsyncResult

import utils
from celery_task import app

if __name__ == __main__:
    # 通过指定任务的id, 指定开启任务的worker实例化一个异步对象. 当一有结果就可以.get获取到对应任务的返回结果.
    while True:
        task_id = utils.conn.brpop(task_id)[1]
        import time
        time.sleep(0.5)   # 这里就是没办法知道worker什么时候将当前执行任务的id执行成功.

        print(task_id:, task_id, type(task_id))  # task_id: c72c2454-6232-477b-986b-3f896e752088 <class ‘str‘>
        async_obj = AsyncResult(id=task_id, app=app)
        if async_obj.successful():
            result = async_obj.get()
            print(result)
        elif async_obj.failed():
            print(任务失败)
        elif async_obj.status == PENDING:
            print(任务等待中被执行)
        elif async_obj.status == RETRY:
            print(任务异常后正在重试)
        elif async_obj.status == STARTED:
            print(任务已经开始被执行)

 5 注意事项

# from scripts.celery_task import task2
# from scripts.celery_task import task1
‘‘‘
celery_task作为包, 被命令执行时. 如果不将celery_task作为定级导入, 那么任务的执行将会是未被注册的. 任务将不会被运行的worker获取, 将会抛出异常.
[2020-07-26 19:40:56,983: ERROR/MainProcess] Received unregistered task of type ‘scripts.celery_task.task2.task2‘.


因此, 为了在项目中能够在任意位置都可以执行任务. 因此celery_task必定要放在项目的根目录下的. 那么无论在任何位置导入, 都是没有问题的. 如下:
    from celery_task.a.b.c.d import xxx
    
    如果不是在项目的根目录下, 你的导入也许是这样的.
    from scripts.celery_task import task
    那么worker将找不到你指定的任务的路径. 

本质: 就是由于采用了django的反射机制,使用celery.py所在的celery_task包必须放置项目的根目录下.
‘‘‘

 

celery

标签:back   中文   bsp   include   push   返回结果   return   port   反射   

原文地址:https://www.cnblogs.com/xupengjun/p/14254585.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!