基于Redis配置Celery

数据库 其他数据库 Redis
作为一个分布式异步计算框架,Celery虽然常用于Web框架中,但也可以单独使用。虽然常规搭配的消息队列是RabbitMQ,但是由于某些情况下系统已经包含了Redis,那就可以复用。

作为一个分布式异步计算框架,Celery虽然常用于Web框架中,但也可以单独使用。 虽然常规搭配的消息队列是RabbitMQ,但是由于某些情况下系统已经包含了Redis,那就可以复用。

以下撇开Web框架,介绍基于Redis配置Celery任务的方法。 

  1. pip install celery[redis] 

项目结构 

  1. $ tree your_project  
  2. your_project  
  3. ├── __init__.py  
  4. ├── main.py  
  5. ├── celery.py  
  6. └── tasks.py  
  7. 0 directories, 4 files 

其中,main.py是触发Task的业务代码。当然,文件名可以随意改。celery.py是Celery的app定义的位置,tasks.py是Task定义的位置,文件名不建议修改。

配置Celery

在celery.py中写入如下代码: 

  1. from celery import Celery  
  2. from .settings import REDIS_URL  
  3. APP = Celery 
  4.     main=__package__ 
  5.     broker=REDIS_URL 
  6.     backend=REDIS_URL 
  7.     include=[f'{__package__}.tasks'],  
  8.  
  9. APP.conf.update(task_track_started=True

其中,REDIS_URL从同一的配置settings.py中引入, 形式大概是redis://localhost:6379/0。这里既用Redis来当broker,又用来当backend。即,既当消息队列,又当结果反馈的数据库(默认仅保存1天)。

在include=,需要填一个下游worker的包名列表。这里选择了同一个包的tasks.py文件。

额外设置的task_track_started,是命令Worker反馈STARTED状态。默认情况下,是无法知道任务什么时候开始执行的。

编写任务并调用

在tasks.py文件中,添加异步任务的实现。 

  1. from .celery import APP  
  2. @APP.task  
  3. def do_sth():  
  4.     pass 

在需要发起任务的地方,用.apply_async可以触发异步调用。即,实际只是向消息队列发送消息,真正的执行操作在远程。 

  1. from celery.result import AsyncResult  
  2. from .tasks imprt do_sth  
  3. result = do_sth.apply_async()  
  4. assert isinstance(result, AsyncResult) 

运行Worker: 

  1. celery -A your_project worker 

运行原理

一次Task从触发到完成,序列图如下:

其中,main代表业务代码主进程。它可能是Django、Flask这类Web服务,也可能是一个其它类型的进程。worker就是指Celery的Worker。

main发送消息后,会得到一个AsyncResult,其中包含task_id。仅通过task_id,也可以自己构造一个AsyncResult,查询相关信息。其中,代表运行过程的,主要是state。

worker会持续保持对Redis(或其它消息队列,如RabbitMQ)的关注,查询新的消息。如果获得新消息,将其消费后,开始运行do_sth。运行完成会把返回值对应的结果,以及一些运行信息,回写到Redis(或其它backend,如Django数据库等)上。在系统的任何地方,通过对应的AsyncResult(task_id)就可以查询到结果。

Celery Task的状态

以下是状态图:

其中,除SUCCESS外,还有失败(FAILURE)、取消(REVOKED)两个结束状态。而RETRY则是在设置了重试机制后,进入的临时等待状态。

另外,如果保存在Redis的结果信息被清理(默认仅保存1天),那么任务状态又会变成PENDING。这在设计上是个巨大的问题,使用时要做对应容错。

常见控制操作 

  1. result = AsyncResult(task_id)  
  2. # 阻塞等待返回  
  3. result.wait()  
  4. # 取消任务  
  5. result.revoke()  
  6. # 删除任务记录  
  7. result.forget() 

有时,在业务主进程中需要等待异步运行的结果,这时需要使用wait。如果要取消一个排队中、或已执行的任务,则可以使用revoke。即使任务已经执行完成,也可以使用revoke,但不会有任何变化。如果需要提前删除任务记录,可以使用forget。 

 

责任编辑:庞桂玉 来源: 马哥Linux运维
相关推荐

2015-07-23 16:38:56

Redis

2022-09-16 11:23:59

Python框架Celery

2016-12-19 14:59:00

redis.conf配置事例数据

2011-11-25 11:23:29

IPsec VPNIPsec VPN配置

2017-07-11 13:30:12

RedisDockerLinux

2023-12-30 13:47:48

Redis消息队列机制

2023-07-03 07:55:25

2022-01-27 20:15:31

集群存储元数据

2020-02-07 09:44:30

Redis哨兵数据库

2021-10-30 19:30:23

分布式Celery队列

2011-03-08 11:08:55

VLAN

2017-03-20 15:08:04

RedisNoSQLcentos6

2012-10-30 10:09:56

Redis

2019-03-18 14:58:18

RedisMySQLMongoDB

2020-06-03 16:44:28

RedisJava技术

2009-06-14 16:59:16

ibmdwWebSphere

2023-03-06 10:42:45

2022-03-08 15:24:23

BitMapRedis数据

2016-10-28 08:39:23

WebHook运维工具

2009-12-09 13:35:09

静态路由配置
点赞
收藏

51CTO技术栈公众号