Celery使用过程中遇到的一些问题

开发 项目管理
做项目时,其中用了Celery这种工具。前段时间,遇到过一些问题,解决后没有进行总结,今天就抽个空把它记录下来。

 [[335445]]

本文转载自微信公众号「新钛云服」,作者黄平安 。转载本文请联系新钛云服公众号。

做项目时,其中用了Celery这种工具。前段时间,遇到过一些问题,解决后没有进行总结,今天就抽个空把它记录下来。

用过Celery的程序员,都知道它是一种异步执行程序的工具。里面有Worker、Task等概念,这里我就不赘述了。

1、功能需求

在使用Celery的过程中,我需要知道Task的状态。Task就是异步任务,用户没执行一次异步任务,就会新创建一个Task,代表此异步任务。

该Task对象中,包含着许多信息,其中也包括状态。我的项目中,需要根据Task的状态来判断,这次异步任务是否还在执行中。

2、 出现问题

既然,我需要Task的状态,那我就需要查看Task的状态怎么获取啊!我查看了一下Celery的源码!发现在Celery的AsyncResult对象中,有个state字段。如下图所示:

根据,该源码中的注释说明,该字段有好几个值。分别是:PENDING、STARTED、RETRY、FAILURE、SUCCESS。

 

然后,我就赶紧写个demo验证一下,看看这个state字段是不是我想要的。demo如下:

 

我执行项目中的Celery异步任务,根据我之前查出来的task id。执行demo查询该Task的状态。

这时候,问题就出来了,根据demo返回的Task状态为PENDING。表示Task还在等待中,尚未执行。

这就不对了,此时的状态应该是STARTED,因为我的Task已经执行好一段时间了,它返回的结果不准确。

3、 解决问题

难道我用的字段不正确,然后我就谷歌搜索。发现Celery官网和网上的大多数反馈也是表示Task的状态字段就是state。

那我为什么测出的结果和理论的不同呢?然后,我详细查看Celery的配置,发现了一个参数:CELERY_TRACK_STARTED。

该参数默认是关闭的,表示只要Celery开始执行Task就会追踪该Task。所以,开启该参数后,Task的状态是时刻记在BACKEND中的。

好,我在Celery的配置文件处,加了该参数。

 

然后再执行Celery的异步任务,得到的结果是我想要的。

4、 引申思考以及问题

我的问题是解决了,但是这引起了我对Celery的一些兴趣。

当时,我就考虑到,如果我把正在运行中的Task任务,直接kill掉。那么此时我再去看Task的状态,它会是啥呢?

STARTED,正在执行中的状态。

而此时,Task已经关掉,它不应该是这种状态。为此,我猜测这应该是,Task意外结束,没有改变Task的状态导致的。

但是这样就不太好了,因为只要是程序,那它就一定有意外退出的可能。假设,我的项目需要查看Task的状态,当Task被意外kill掉时,项目中查看Task的状态就不准确了。

5、 引申问题解决思路一

当时我想:既然Task被kill掉之后,还能显示运行中,说明此Task的状态一定是保存在某个地方,我把该Task的数据清空了不就完了。

而Celery的数据存储,只有可能存在三个地方:使用RabbitMQ的消息代理(BROKER),使用Redis的任务结果保存处(BACKEND),以及文件保存(当然这点基本上没可能,Celery没这样用过,我主要是死马当活马医)。

这三个地方,其实只有Redis可能存放Task的状态,按照Celery的机制,也只有它最有可能存放。

但是呢?为了弄清Celery的存储机制,我想试试Celery会把数据存到RabbitMQ中吗?然后,我执行了,以下命令,清空RabbitMQ队列。

 

此时,RabbitMQ队列的数据已经为空。然后我查看Task的状态,依然还为STARTED。说明不是它存储Task的状态。

然后,我进入redis中。使用keys *命令,发现许多带有celery-task-meta前缀的记录。

 

后经查明,这些记录的后缀就是Celery中Task的id。

我根据我的Task的id,查出如下内容:

我们能清晰的看出,内容中Task的状态为STARTED。这说明的确是存放在Redis中的。然后,我把这条记录删除,再执行demo,Task的状态不再是STARTED,项目中显示的状态就正确了。

 

但是,这又引出了一个问题,怎么删除这条记录,或者什么时候删除这条记录。当然,我们删除很容易,编程语言的redis模块或者Celery自己提供的代码都能删除。Celery中根据task id删除backend中的数据。

 

那么,什么时候删除这条记录呢?Celery默认的是保留此数据24小时。我左思右想,还是不删这条记录了。换种思路解决这个问题吧!

6、 引申问题解决思路二

要知道,Celery的Task是运行在Worker上的。只要判断此时的Worker程序是否还正常运行,不就可以判断Task的状态是否还在运行中了吗?

说干就干,我们通过ps命令,可以查看Celery运行的程序。

 

然后,我们执行task时,把它本身运行的程序进程pid记录下来,发现正好就是Worker的进程pid。

这样就简单了,我们只需要结合Celery提供查看Task状态的接口,以及Python提供的Psutil查看进程的模块。就能最终判断Task是不是真在运行中。只有Task的状态为STARTED,并且Task所在的Worker进程在运行中,Task才是真正在运行状态。

Psutil查看进程是否运行代码如下:

 

7、 总结

今天只是把我前段时间遇到的问题以及解决思路记录下来,也没写Celery的内部机制等等,这些东西网上一大把,我也不是很有写它们的必要。

做过几年的程序员,感触最多的就是解决问题的思路。一旦遇到某个问题了,一种思路解决不了,可以换种思路解决,另一种思路可能也不一定能完美解决,但可以加深对问题的理解。而怎么想到另一种思路,就需要平时的多积累和提高自己的认知范围了,这还是比较难的。

 

责任编辑:武晓燕 来源: 新钛云服
相关推荐

2016-03-23 11:03:40

2021-11-15 15:43:28

Windows 11升级微软

2024-09-09 08:02:27

2010-06-07 16:51:06

rsync 使用

2011-03-04 13:49:38

FileZilla

2011-04-13 13:54:03

HttpClient

2022-01-16 08:04:44

集群部署canal

2009-12-29 14:14:22

2011-03-08 14:28:03

proftpdGentoo

2022-02-07 00:10:28

Docker容器开发

2018-04-12 09:29:56

HTTP服务器问题

2017-07-03 17:20:55

Android软键盘控制开发问题

2016-10-18 22:10:02

HTTP推送HTML

2010-05-11 19:01:11

Unix系统

2009-06-12 10:25:42

Webservices

2018-06-12 15:39:41

容器部署云平台

2009-11-02 08:56:17

2017-10-13 12:23:17

苹果

2010-06-29 16:56:49

SQL Server数

2009-08-06 16:01:30

C#接口成员
点赞
收藏

51CTO技术栈公众号