Celery

Celery

在一个应用服务中,对于时效性要求没那么高的业务场景,我们没必要等到所有任务执行完才返回结果,例如用户注册场景中,保存了用户账号密码之后,就可以立即返回,后续的账号激活邮件,可以用一种异步的形式去处理,这种异步操作可以用队列服务来实现。否则,如果等到邮件发送成功可能几秒过去了。

Celery 是什么?

Celery 是Python语言实现的分布式队列服务,除了支持即时任务,还支持定时任务,Celery 有5个核心角色。

Task

任务(Task)就是你要做的事情,例如一个注册流程里面有很多任务,给用户发验证邮件就是一个任务,这种耗时的任务就可以交给Celery去处理,还有一种任务是定时任务,比如每天定时统计网站的注册人数,这个也可以交给Celery周期性的处理。

Broker

Broker 的中文意思是经纪人,指为市场上买卖双方提供中介服务的人。在Celery中这个角色相当于数据结构中的队列,介于生产者和消费者之间经纪人。例如一个Web系统中,生产者是主程序,它生产任务,将任务发送给 Broker,消费者是 Worker,是专门用于执行任务的后台服务。Celery本身不提供队列服务,一般用Redis或者RabbitMQ来实现队列服务。

Worker

Worker 就是那个一直在后台执行任务的人,也成为任务的消费者,它会实时地监控队列中有没有任务,如果有就立即取出来执行。

Beat

Beat 是一个定时任务调度器,它会根据配置定时将任务发送给 Broker,等待 Worker 来消费。

Backend

Backend 用于保存任务的执行结果,每个任务都有返回值,比如发送邮件的服务会告诉我们有没有发送成功,这个结果就是存在Backend中,当然我们并不总是要关心任务的执行结果。

celery

记住这5个角色后面理解Celery就轻松了。

这里面 异步任务、定时任务可以由各个服务器发起,定时任务可以由 celery 代理发起,woker 可以由多个 celery 处理。

异步任务

假设我们选择Redis作为broker。

  1. 创建celery实例,创建任务
# tasks.py
from celery import Celery

# 1. 创建celery 实例
app = Celery('tasks', broker='redis://localhost:6379', backend='redis://localhost:6379')


# 2. 创建任务
@app.task
def task1(args):
    import time
    # 模拟复杂操作
    time.sleep(2)
    return 'success'

  1. 启动worker

启动Worker,监听 Broker 中是否有任务,命令:celery worker,你可能需要指定参数

-A: 指定 celery 实例所在哪个模块中,例子中,celery实例在tasks.py文件中,启动成功后,能看到信息

函数用app.task 装饰器修饰之后,就会成为Celery中的一个Task。

celery -A tasks worker --loglevel=info
  1. 调用任务
# user.py
from tasks import task1


def func():
    task1.delay('任务开始')


if __name__ == '__main__':
    func()

在主程序中,调用函数的.delay方法

目录结构

── celery_test
   ├── tasks.py
   └── user.py

运行 python user.py, 启动应用程序

注意:

  1. celery4 不支持windows,win环境选用celery3版本 或者安装 eventlet 模块 使用命令celery -A <projectname> worker -l info -P eventlet 启动celery
  2. 如果使用 python3.7 与 celery3 ,kombu 中有async 关键字 与python3.7 冲突,需要将 kombu 中 async 模块替换个名字(async_) ,并将源码中所有用到的地方全部替换

周期任务

import datetime
import time

from tasks import task1


def func2():
    """10s后调用任务"""
    # 定时任务我们不在使用delay这个方法了,delay是立即交给task 去执行
    # 现在我们使用apply_async定时执行

    # 获取当前时间 此时间为东八区时间
    ctime = time.time()
    # 将当前的东八区时间改为 UTC时间 注意这里一定是UTC时间
    utc_time = datetime.datetime.utcfromtimestamp(ctime)
    # 为当前时间增加 10 秒
    add_time = datetime.timedelta(seconds=10)
    action_time = utc_time + add_time

    # action_time 就是当前时间未来10秒之后的时间
    # 现在我们使用apply_async定时执行
    res = task1.apply_async(args=('func2',), eta=action_time)
    print(res.id)


if __name__ == '__main__':
    func2()
    print(1)

直接运行此文件,就可以发送定时任务给 celery

定时任务

配置 CELERYBEAT_SCHEDULE 参数

CELERYBEAT_SCHEDULE = {
    'add-every-3-seconds': {
        'task': 'celery_app.task1.add',
        'schedule': timedelta(seconds=3),  # 每 3 秒执行一次
        'args': (5, 8)  # 任务函数参数
    },
    'multiply-at-some-time': {
        'task': 'celery_app.task2.multiply',
        'schedule': crontab(hour=9, minute=50),  # 每天早上 9 点 50 分执行一次
        'args': (3, 7)  # 任务函数参数
    }
}

执行命令

celery_demo $ celery -A celery_app worker --loglevel=info
celery_demo $ celery beat -A celery_app
# 或者
$ celery -B -A celery_app worker --loglevel=info
# 若修改代码,需要重启 worker 和 beat

详情异步任务神器 Celery

参考

高性能异步框架Celery入坑指南

异步任务神器 Celery

celery有什么难理解的?

Celery 初步

posted @ 2019-08-10 00:30  写bug的日子  阅读(140)  评论(0编辑  收藏  举报