如何在 Flask 的 Factory Mode 中使用 Celery?

2018-07-17 08:15:40 +08:00
 mrchi

如题,诉求是,能够在 Celery 中正常使用 Flask 的上下文。按照 Flask 文档 Celery Background Tasks 的示例,在 Celery App 创建和修改 Task 类的时候需要 Flask App。这就有一个死循环:

不知道大家都是怎么做的? 我自己实现了一个丑陋的方法——flask-with-celery-example,大家给给意见有没有漏洞或者 bug 啥的。


刚刚想到另一种方法是:

5939 次点击
所在节点    Flask
20 条回复
rogwan
2018-07-17 08:31:29 +08:00
看任务类型吧,如果必须要和 flask 结合,那只能用 flask 的 App 上下文进行绑定。如果只是一些独立的异步任务,是可以做成独立的 celery App。
greyli
2018-07-17 09:00:00 +08:00
1. 建议的处理方式:Celery 实例全局创建; Celery 配置加载和 Task 上下文重写在 Flask 工厂函数中进行。
2. 新版本( 4 )的 Celery 中的配置采用小写形式,不能通过 Flask 的配置对象读取,所以建议将两者的配置分开处理。
mrchi
2018-07-17 09:19:18 +08:00
@rogwan 要和 Flask 结合的一大原因是,用了 Flask-SQLAlchemy,操作数据库用到 db,所以不好独立。
mrchi
2018-07-17 09:24:16 +08:00
@greyli 好的,我试一下
hotea
2018-07-17 09:28:17 +08:00
目前我是这样搞的,celery_app 在使用的时候创建,创建时传入的参数是一个新的 flask_app.

https://paste.ofcode.org/ueVCWz355YudaPKa5NaqJE
vZexc0m
2018-07-17 09:35:02 +08:00
可以独立于 flask, 可以使用 with application.app_context()提供上下文
hotea
2018-07-17 09:37:13 +08:00
上面这种方式有个注意点地方就是在视图中需要发送任务( tasks.foo.delay(*args, **kw),而在 import tasks 时,tasks 的导入语句要在蓝图之下,否则会循环导入。

还有另外一种发送任务的方式:在视图函数里现用现生成 task_app, 然后 task_app.send_task('tasks.foo'), kwargs={})这种将任务执行函数以文本形式传入。使用起来不如第一种方便,但这种没有循环导入
mrchi
2018-07-17 10:31:11 +08:00
@hotea 这种我看到过,如果使用自动化测试工具的话,会不会造成 Celery 应用的 Flask app 环境配置与实际运行的 Flask App 环境配置不一致呢
mrchi
2018-07-17 10:34:13 +08:00
@vZexc0m 如果在每个 task 里写的话,感觉相当繁琐,如果重写 celeryapp.task,那么就要拿到 application 了。感觉 2#的方法不错的。
GoLand
2018-07-17 13:02:55 +08:00
Celery 就不应该依赖 Flask App,也不用什么 flask-sqlalchemy,直接用 sqlalchemy 不可以么,另外这些配置都单独写,别全部绑在 flask app config 上。并且 celery 和 sqlalchemy 都全局实例化。这样就不存在什么问题了吧。另外,view 层就不应该直接调用 task 吧,再封装一层代理,view 层所有接口都走那层。

https://github.com/Robpol86/Flask-Large-Application-Example

可以看看这个组织方式。还不错。
rogwan
2018-07-17 13:28:36 +08:00
@GoLand 有时候没办法,任务请求是从 flask 来的,必须要绑定 flask app
mrchi
2018-07-17 14:16:48 +08:00
@GoLand flask-sqlalchemy 对 sqlalchemy 的一些封装,还是很好用的,比如 pagination。
mrchi
2018-07-17 14:29:59 +08:00
@greyli

- 将 broker_url,result_backend 等配置可以放在 Flask 配置中,方便不同环境使用不同的 broker 配置,防止任务混乱;
- 其他的配置可以单独写文件存放。

这样如何?
est
2018-07-17 14:30:11 +08:00
flask 为了 url 能 decorator 一个便利,制造了 n 多麻烦。LZ 的问题就是一例。
brucedone
2018-07-17 16:27:55 +08:00
不推荐将类似 message queue 或者 task queue 与 flask 绑定 ,另外 celery 略重,可以考虑轻量级的 python-rq,方便好用,简单明了,等到了真正不满足的时候再考虑换 celery
greyli
2018-07-17 19:31:28 +08:00
@mrchi 这样也不错,不过据我所知,Flask 不会读取小写形式的配置变量,需要注意一下。
sunhk25
2020-01-10 10:59:36 +08:00
想问下楼主有没有什么方法把以下两个任务一块启动
celery worker -A manage:add_app -l info
celery worker -A manage:factorial_app -l info


分开的话有以下错误
KeyError: 'app.celerytasks.add.my_add'
KeyError: 'app.celerytasks.factorial.my_factorial'
mrchi
2020-01-12 10:06:56 +08:00
@sunhk25 不会吧,我当时测正常的,你是在哪个目录下执行的命令呢?
sunhk25
2020-01-14 08:35:09 +08:00
我是在项目根目录 flask-with-celery-example 下执行的命令
※有一点不同的是我是用 virtualenv 建的虚拟环境
好像确实是应不是在同一个文件中引发的错误,查了一下
好像需要配置加载项 app.config['imports']
https://www.jianshu.com/p/807efde55d81
sunhk25
2020-01-14 09:01:08 +08:00
我用的 celeryV4
添加任务的命令改了一下就可以了
# @add_app.task(shared=False)
@add_app.task

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/471458

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX