在使用 Flower 的时候,可能你也发现了,Flower 支持一种可以作为 Celery 子命令执行,可能你惊讶过,但是,它是如何实现的,你了解么?本文将向你 Flower 是如何实现这个功能的。
以前在使用 Flower 的时候,我也惊奇居然还有这种玩法,当初搜了一圈,发现只有 Celery 自己的文档有做介绍,虽然只做了一点点介绍,但是,至少是可操作的。官方的文档在Extensions and Bootsteps
最近因为要为 CeleryBeatRedis 写一个CRUD 任务的Admin,希望以类似 Flower 的方式实现,所以重新回顾了这个内容,顺便总结一番给大家分享一下,顺带一提,刚才的文档有两块内容,一块就是本文要讲的 扩展
,另一块就是以后也会总结的Bootsteps
了。
可能以下较多内容都会引用官方文档,但会加以自身理解进行丰富简化。
给 Celery 添加子命令
要给 Celery 添加新的子命令,需要使用到的工具是 setuptools
的 entry-points
,Entry-points
是 setup.py
文件中的一个特别的元数据,当你安装完成之后,你可以使用 pkg
资源模块读取到它。
Celery 能够识别被安装为 celery.commands
的 entry-points,但是,这个值必须指向 celery.bin.base.Command
的合法子类,否则,Celery 会哭给你看。
官方文档并没有太多关于继承的资料,但是,根据我读源码的经验,事实上,你最小只需要实现 run_from_argv
即可。函数原型为:
def run_from_argv(self, prog_name, argv, command=None)
因为源码调用是这样的:
return cls(
app=self.app, on_error=self.on_error,
no_color=self.no_color, quiet=self.quiet,
on_usage_error=partial(self.on_usage_error, command=command),
).run_from_argv(self.prog_name, argv[1:], command=argv[0])
所以,你应该以此为入口开始编写代码逻辑。
下面是一个注册 celery ceexample
命令的 setup.py
精简示例文件,虽然如此精简,但是完全可以保证你可以验证这个机制。
from setuptools import setup, find_packages
setup(
name='ceexample',
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
entry_points={
'celery.commands': [
'ceexample = ceexample.command:ExampleCommand',
],
},
)
entry_points 的定义就是一个字典,然后 key 应该是 celery.commands
, 值的话是个字符串数组,里面是一个个等式
- 等式左边是我们要注册的子命令,例如我们这次要注册的就是
celery ceexample
- 等式右边是响应这个子命令的类,也就是我们自定义的类的位置,之前说了,必须是
Command
的子类,并且实现了需要的方法。 - 指定子类的方式是比较通用的,冒号前半部分是模块路径,冒号后半部分是模块中类的名字,中间用冒号隔开
然后是编写代码,整个的目录结构是这样的:
.
├── ceexample
│ ├── __init__.py
│ └── command.py
└── setup.py
作为必须的 `_init_.py文件中是没有内容的,然后
command.py` 文件中的内容也是异常简单:
from celery.bin.base import Command
class ExampleCommand(Command):
def run_from_argv(self, prog_name, argv=None, command=None):
print "run_from_argv called...."
至此,整个代码就算是编写完毕了,这个时候可以安装下试试,只需要使用一下安装命令:
python setup.py install
然后你可以直接先敲一个 celery
命令试一下,你会发现是输出一序列的说明,拉到最后面,你会发现这样的东西:
图 1:Celery 扩展示例 |
说明我们的扩展是注册成功啦,然后尝试运行一下:
celery ceexample
如果不出意外的话,控制台打印出来的应该是:
run_from_argv called....
Celery 扩展就讲到这,内容也差不多就这么多了。
扩展知识
entry_points 中
celery.commands
在安装后发生了什么?这个问题稍微有点复杂,我在另外一篇关于 setup.py 的文章有一些介绍,如果感兴趣可以参考一下。
除了实现 run_from_argv 外还只实现其他方法么?
事实上,Celery 中的 Command 实现了大部分方法的代码,所以,你完全可以实现其他方法,但是,官方文档是不会跟你介绍有哪些方法的,所以只能你自己去看代码去找。
需要说明的是,最后的最后,
run
方法是你需要重写的,因为如果你什么都不写得话,将会在这个方法报错。在扩展里面如何拿到 Celery 的数据
因为扩展的类是继承自
celery.bin.base.Command
的,所以我们完全可以无条件得拿到 Command 类中的数据,这当然包括 Celery 的实例对象self.app
。拿到这个对象后,我们可以获取的数据就非常多了,例如消息队列,结果队列的地址,等等。。