怎么实现 Django 在启动完成之后调起线程去监听数据源?困扰太久,求戳

2017-11-07 08:56:16 +08:00
 toono

需求 :在写的一个服务基于 Django 框架,有 http 请求的处理和监听 Kafka 的消息队列。为了解决题目提出的问题还集成了 celery,但是还没找到合适的用法。我是希望 Django 程序启动结束之后就调用我写好的创建线程或者进程的函数( Django 未启动完成运行 Kafka 监听的代码会提示未加载完成的错误)。

我现有的方案是在 celery 的 tasks 编写一个 sharetask 去执行启动监听线程的方法。然后 task 的调用写在 urls.py 。项目启动完成之后就会运行目标代码。

但是上面的方案会导致我启动线程的代码被执行两次,影响到了我监听的处理逻辑。

看到的其他方法:

  1. 查到有人提到可以用 middleware,但是觉得这不是 http 请求生命周期里面的工作,觉得不适用。
  2. 也看到用 AppConfig 的,但是重载这个的 ready 方法,去执行我的函数,会提示未加载完成错误,也不适用。

所以请教各位大大有什么更好的方法?

7350 次点击
所在节点    Python
22 条回复
janxin
2017-11-07 09:02:55 +08:00
你想把 celery 的异步动作变成同步监听?
toono
2017-11-07 09:10:05 +08:00
@janxin 不是,我的想法是用 celery 启动线程去监听。如果造成了 celery 同步阻塞就不是我希望的效果了。

我的想法就是监听 Kafka 的消息,然后对消息进行处理。

集成上了 celery 可能是多余的,但是对处理这种情景没有经验,比较无头绪。
Tinet
2017-11-07 10:15:12 +08:00
http 请求的处理和监听 Kafka 的消息队列,不应该分成两个系统来完成么?
wcsjtu
2017-11-07 10:19:11 +08:00
WSGIServer 和 uwsgi 启动顺序是不一样的,middleware 在 master 中 load, 业务代码在 worker 中 load。按照你说的, 你的启动代码只能写在 middleware 所在的文件里了。
这样,就是在 master 进程里开了个线程, 你确定这是你想要的?
推荐用 celery 解决
最后一点建议, 不要在 django 全局位置开线程,django 一般都是工作在多进程模式下的。
walleL
2017-11-07 10:23:04 +08:00
消息处理独立成一个进程不好吗?
提示未加载完成错误 ——这是指 Django 的环境未初始化的报错?
manzhiyong
2017-11-07 10:24:28 +08:00
你如果只是想用到 django 的 orm,那么建一个 command,按照后台进程启动就行了。
lxguidu
2017-11-07 10:26:44 +08:00
放在 urls.py 里肯定不行的,你试下看看 execute_from_command_line(sys.argv)的代码
toono
2017-11-07 10:35:55 +08:00
@Tinet 本来处理的业务就不多了,再分的话整个系统太散了,而且我觉得这个需求是可以实现的。
toono
2017-11-07 10:37:12 +08:00
@wcsjtu 我使用上了 celery 了,但是还不确定在哪个地方对 task 执行 delay 方法好。
toono
2017-11-07 10:38:55 +08:00
@walleL 独立成进程的话会跟随 Django 关闭吗?这一点我不太确定。

是的,为初始化的报错。
toono
2017-11-07 10:41:00 +08:00
@manzhiyong Django 的 http 服务我还是要的。
pixstone
2017-11-07 10:42:28 +08:00
我们一般是开两个应用来处理。
从 kafka 收到消息后,再丢给 celery 处理,或者直接处理。
toono
2017-11-07 10:47:18 +08:00
@pixstone 我现在就相当于混淆起来了。

因为使用到了 Django 的 orm 和 http 服务,所以才没有分开来。都是小的功能,如果都分开来就太零散了,打算有了瓶颈的时候才重新设计。
wcsjtu
2017-11-07 10:47:44 +08:00
@toono celery 会 load 你的代码,写在哪里都可以。views,models 都可以。
chocho
2017-11-07 10:49:45 +08:00
supervisor 另起一个进程
laoyur
2017-11-07 10:51:16 +08:00
@toono #10 未初始化的报错
我是这么绕过的,import 各种模块,放到 ready 中,而不是放到文件顶部
toono
2017-11-07 10:54:06 +08:00
@wcsjtu 感谢!突然发现新大陆
pixstone
2017-11-07 11:04:46 +08:00
Python GIL 就是你的瓶颈(笑,所以不开线程处理,还会影响 HTTP 部分的服务质量 。 其实可以考虑用 async 来处理。 不过我自己一直没调通。或者 stackless ( pypy 版集成了)

所以 supervisor 另起一个进程是一个最简单,性能不会有风险的解决方案。 毕竟 Python 是 Python,不是 Java 后台开一堆线程池处理的,大家都在一个 JVM 干活的模式。
toono
2017-11-07 11:10:54 +08:00
@pixstone 嗯😂,所以现在打算 supervisor + celery 来解决这个需求。多谢了~
toono
2017-11-07 11:12:23 +08:00
@laoyur 我继续用 celery 去解决这个问题了,用 AppConfig 我觉得逻辑不是很清晰。

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

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

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

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

© 2021 V2EX