Celery

1. Celery介绍

  • Celery介绍:

    • 一个简单、灵活且可靠、处理大量消息的分布式系统,可以在一台或者多台机器上运行。
    • 是一个基于生产者消费者设计模式的实现异步消息处理的系统
    • 单个 Celery 进程每分钟可处理数以百万计的任务。
    • 通过消息进行通信,使用消息队列(broker)客户端消费者之间进行协调。
  • 安装Celery:

    $ pip install -U Celery

 

2. Celery的使用

 2.1 定义启动文件main.py

# 导入Celery
from celery import Celery

# 创建Celery实例
celery_app = Celery("meido")

 

 2.2 定义配置文件config.py,并在启动文件中加载配置

# 指定消息队列的位置
broker_url= 'redis://127.0.0.1:6379/10'
  • broker_url为固定写法

启动文件中添加加载配置文件的代码:

# 导入Celery
from celery import Celery

# 创建Celery实例
celery_app = Celery("meido")

# 加载配置
celery_app.config_from_object("celery_tasks.config")

 

2.3 定义任务,并在启动文件中注册任务

创建sms包并定义tasks.py文件:

在tasks.py文件中定义任务:

from celery_tasks.sms.yuntongxun.ccp_sms import CCP
from . import constants
from celery_tasks.main import celery_app
# name:异步任务别名
@celery_app.task(name='ccp_send_sms_code')
def ccp_send_sms_code(mobile, sms_code):
    """
    发送短信异步任务
    :param mobile: 手机号
    :param sms_code: 短信验证码
    :return: 成功0 或 失败-1
    """
    send_ret = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
    return send_ret
  • 文件名tasks.py为固定写法
  • @celery_app.task对应celery实例的task装饰器

 启动文件main.py中注册任务

# 导入Celery
from celery import Celery

# 创建Celery实例
celery_app = Celery("meido")

# 加载配置
celery_app.config_from_object("celery_tasks.config")

# 注册任务
celery_app.autodiscover_tasks(["celery_tasks.sms"])

2.4 启动Celery服务

 虚拟环境下:

cd ~/projects/meiduo_project/meiduo_mall
celery -A celery_tasks.main worker -l info

window系统下,可能出现消息不消费情况,此时,需要使用如下命令启动:

celery -A celery_tasks.main worker --pool=solo -l info

说明:

  • -A指对应的应用程序, 其参数是项目中 Celery实例的位置。
  • worker指这里要启动的worker。
  • -l指日志等级,比如info等级。

启动日志如下:

(py3_django) D:\work\meiduo-project\meiduo_mall>celery -A celery_tasks.main worker --pool=solo -l info

 -------------- celery@DESKTOP-OT3BAUF v5.0.5 (singularity)
--- ***** -----
-- ******* ---- Windows-10-10.0.18362-SP0 2021-03-08 22:58:31
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app:         meido:0x16406930a90
- ** ---------- .> transport:   redis://127.0.0.1:6379/10
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 4 (solo)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]
  . ccp_send_sms_code

[2021-03-08 22:58:31,180: INFO/MainProcess] Connected to redis://127.0.0.1:6379/10
[2021-03-08 22:58:31,180: INFO/MainProcess] mingle: searching for neighbors
[2021-03-08 22:58:32,211: INFO/MainProcess] mingle: all alone
[2021-03-08 22:58:32,211: INFO/MainProcess] celery@DESKTOP-OT3BAUF ready.

 

2.5 异步调用,发送任务给Celery

# 发送短信验证码
# CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
# Celery异步发送短信验证码
ccp_send_sms_code.delay(mobile, sms_code)

说明:

  •  ccp_send_sms_code为Celery任务定义中的方法,此处使用.delay调用完成异步发送任务给Celery

控制台显示的Celery服务接收任务并执行的日志:

(py3_django) D:\work\meiduo-project\meiduo_mall>celery -A celery_tasks.main worker --pool=solo -l info

 -------------- celery@DESKTOP-OT3BAUF v5.0.5 (singularity)
--- ***** -----
-- ******* ---- Windows-10-10.0.18362-SP0 2021-03-08 22:58:31
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app:         meido:0x16406930a90
- ** ---------- .> transport:   redis://127.0.0.1:6379/10
- ** ---------- .> results:     disabled://
- *** --- * --- .> concurrency: 4 (solo)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]
  . ccp_send_sms_code

[2021-03-08 22:58:31,180: INFO/MainProcess] Connected to redis://127.0.0.1:6379/10
[2021-03-08 22:58:31,180: INFO/MainProcess] mingle: searching for neighbors
[2021-03-08 22:58:32,211: INFO/MainProcess] mingle: all alone
[2021-03-08 22:58:32,211: INFO/MainProcess] celery@DESKTOP-OT3BAUF ready.
[2021-03-08 22:59:23,983: INFO/MainProcess] Received task: ccp_send_sms_code[9734a0d8-312d-478c-a9a7-a5faa090c7cd]
[2021-03-08 22:59:24,295: WARNING/MainProcess] result
[2021-03-08 22:59:24,295: WARNING/MainProcess] {'statusCode': '000000', 'templateSMS': {'smsMessageSid': '3430d32c8b77402da44a220994c1abb7', 'dateCreated': '202103
08225903'}}
[2021-03-08 22:59:24,295: WARNING/MainProcess] 0
[2021-03-08 22:59:24,295: INFO/MainProcess] Task ccp_send_sms_code[9734a0d8-312d-478c-a9a7-a5faa090c7cd] succeeded in 0.3129999999998745s: 0

 2.6 celery任务失败重试机制

# bind:设置为True,实现当前任务对象task会作为第一个参数(self)自动传入
# name:异步任务别名
# retry_backoff:用于计算异常自动重试的时间间隔:第n次间隔时间:(retry_backoff×2^(n-1))s
# max_retries:异常自动重试次数的上限
@celery_app.task(bind=True, name='ccp_send_sms_code', retry_backoff=3)
def ccp_send_sms_code(self, mobile, sms_code):
    """
    发送短信异步任务
    :param mobile: 手机号
    :param sms_code: 短信验证码
    :return: 成功0 或 失败-1
    """
    try:
        send_ret = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
    except Exception as e:
        logger.error(e)
        # 有异常自动重试三次
        raise self.retry(exc=e, max_retries=3)
    if send_ret != 0:
        # 有异常自动重试三次
        raise self.retry(exc=Exception('发送短信失败'), max_retries=3)

    return send_ret

 

3. 补充celery worker的工作模式

  • 默认是进程池方式,进程数以当前机器的CPU核数为参考,每个CPU开四个进程。
  • 如何自己指定进程数: celery worker -A proj --concurrency=4 ,这里--concurrency指定开的进程数,也可简写 -c 来指定 
  • 如何改变进程池方式为协程方式:先安装eventlet模块,然后执行 celery worker -A proj --concurrency=1000 -P eventlet -c 1000 
# 安装eventlet模块
$ pip install eventlet

# 启用 Eventlet 池
$ celery -A celery_tasks.main worker -l info -P eventlet -c 1000
  • 这里指定了开1000个协程

posted @ 2021-03-08 22:05  foreast  阅读(164)  评论(2编辑  收藏  举报