古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。

Python异步任务神器celery

Python admin 105℃ 0评论

Celery 简单来说就是一个分布式消息队列。简单、灵活且可靠,能够处理大量消息,它是一个专注于实时处理的任务队列,同时也支持异步任务调度。Celery 不仅可以单机运行,也能够同时在多台机器上运行,甚至可以跨数据中心。

Celery 中比较关键的概念:

  • worker: worker 是一个独立的进程,任务执行单元,它持续监视队列中是否有需要处理的任务;
  • broker: broker 消息传输中间件,任务调度队列,接收生产者发出的消息,将任务存入队列,broker 负责协调客户端和 worker 的沟通。客户端向队列添加消息,broker 负责把消息派发给 worker。
  • 任务模块:包含异步任务和定时任务,异步任务通常在业务逻辑中被触发并发往任务队列,定时任务由 celery beat 进程周期性发送
  • 任务结果 backend:backend 存储任务执行结果,同消息中间件一样,需要由其他存储系统提供支持

一个典型的 Celery 使用场景就是,当用户在网站注册时,请求可以立即返回而不用等待发送注册激活邮件之后返回,网站可以将发送邮件这样的耗时不影响主要流程的操作放到消息队列中,Celery 就提供了这样的便捷。

安装 Celery

直接使用 python 工具 pip 或者 easy_install 来安装:

安装 Broker

Celery 支持多种 broker, 但主要以 RabbitMQ 和 Redis 为主,其他都是试验性的,虽然也可以使用, 但是没有专门的维护者。如何在 RabbitMQ 和 Redis 之间选择呢?

RabbitMQ is feature-complete, stable, durable and easy to install. It’s an excellent choice for a production environment.

Redis is also feature-complete, but is more susceptible to data loss in the event of abrupt termination or power failures.

Celery 官方明确表示推荐在生产环境下使用 RabbitMQ,Redis 存在丢数据的问题。所以如果你的业务可以容忍 worker crash 或者电源故障导致的任务丢失,采用 redis 是个不错的选择,本篇就以 redis 为例来介绍。

Celery 对于 redis 的支持需要安装相关的依赖,以下命令可以同时安装 celery 和 redis 相关的依赖,但是 redis server 还是必须单独安装的。

Celery 的配置和使用

Celery 本身的配置项是很多的,但是如果要让它跑起来,你只需要加一行配置:

这一行就是告诉 celery broker 的地址和选择的 redis db,默认是 0。接下来用个很简单的例子来介绍 celery 是如何使用的:

上述代码创建了一个 celery 的实例 app,可以通过它来创建任务和管理 workers。在上面的例子中,我们创建了一个简单的任务 task,它返回了两个数相加后的结果。然后启动 celery 服务,通过它来监听是否有任务要处理。

  • -A 选项指定 celery 实例 app 的位置,本例中 task.py 中自动寻找,当然可以直接指定 celery worker -A task.app -l info
  • -l 选项指定日志级别, -l 是 --loglevel 的缩略形式

其他更多选项通过 celery worker –-help 查看

调用任务或者发送消息

然后我们再打开一个 shell 窗口,进入 python 控制台去调用 add 任务:

delay() 是 apply_async 的简写,用于一个任务消息(task message)。我们发现 add 任务并没有返回结果 3,而是一个对象 AsyncResult,它的作用是被用来检查任务状态,等待任务执行完毕或获取任务结果,如果任务失败,它会返回异常信息或者调用栈。

我们先尝试获取任务的执行结果:

报错了:No result backend configured. 错误信息告诉我们没有配置 result backend。因为 celery 会将任务的 状态或结果保存在 result backend,result backend 的选择也有很多,本例中依然选用 redis 作为 result backend。

我们修改 task.py 的代码,添加上 result backend 的设置,保存后重启 celery worker。

然后重新调用 add task:

delay 返回的是一个 AsyncResult 对象,里面存的就是一个异步的结果,当任务完成时result.ready() 为 true,然后用 result.get() 取结果。

任务状态

  • PENDING 任务等待中
  • STARTED 任务已开始
  • SUCCESS 任务执行成功
  • FAILURE 任务执行失败
  • RETRY 任务将被重试
  • REVOKED 任务取消

当我们有个耗时时间较长的任务进行时一般我们想得知它的实时进度,这里就需要我们自定义一个任务状态用来说明进度并手动更新状态,从而告诉回调当前任务的进度。

定时/周期性任务

定时参考:http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#crontab-schedules

链式任务

链式任务中前一个任务的返回值默认是下一个任务的输入值之一 ( 不想让返回值做默认参数可以用 si() 或者 s(immutable=True) 的方式调用 )。

这里的 s() 是方法 celery.signature() 的快捷调用方式,signature 具体作用就是生成一个包含调用任务及其调用参数与其他信息的对象,有点类似偏函数的概念:先不执行任务,而是把任务与任务参数存起来以供其他地方调用。

多个消息队列

启动worker

触发执行

任务调用方式

实际上 delay 只是 apply_async 的快捷方式,只是 apply_async 可以进行更多的任务属性设置,更多参考

关于 AsyncResult 

AsyncResult 主要用来储存任务执行信息与执行结果,有点类似 tornado 中的 Future 对象,都有储存异步结果与任务执行状态的功能。更多参考

Celery Flower

flower 是一个 celery 的监控工具,它提供了一个图形用户界面,可以极大的方便我们监控任务的执行过程, 执行细节及历史记录,还提供了统计功能。

flower 安装

flower 使用简介,首先启动通过命令行启动 flower 进程:

然后打开浏览器 http://localhost:5555/

celery flower

Celery 任务类型

apply_async

调用一个异步任务,这也是最常用的任务类型之一,delay 与它的作用相同,只是 delay 不支持 apply_async 中额外的参数。该方法有几个比较重要的参数,在实际应用中会经常用到:

countdown: 任务延迟执行的秒数,默认立即执行; eta:任务被执行的绝对时间

crontab 计划任务

Celery 同样也支持定时任务:

要启动定时任务,需要启动一个心跳进程,假设

其中 -s 参数指定 celerybeat 文件保存的位置。beat 主要的功能就是将 task 下发到 broker 中,让 worker 去消费。

取消队列中任务

取消队列中任务,可以使用命令行,也可以导入 celery app 然后使用 control()

From:stackoverflow

celery 在 supervisor 中 root 不能启动问题

Celery 不能用 root 用户启动,所以在 supervisor 中启动时会报错:

解决办法

或者 supervisor 配置中

参考文献

转载请注明:北凉柿子 » Python异步任务神器celery

喜欢 (0)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址