V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
toono
V2EX  ›  Python

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

  •  2
     
  •   toono ·
    ToonoW · 2017-11-07 08:56:16 +08:00 · 7510 次点击
    这是一个创建于 2555 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    看到的其他方法:

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

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

    第 1 条附言  ·  2017-11-07 10:44:32 +08:00
    因为使用 celery 不熟练,在 urls.py 下面我直接运行 share_task 装饰的 task 函数了,而不是使用 delay 之类的 task 启动方法,导致了两次运行 task 中的代码。抱歉。

    但是像我的写法我觉得还是不应该的,将非路由逻辑的代码放在 urls.py ,希望 dalao 给出给好的建议。谢谢
    22 条回复    2017-11-07 13:35:47 +08:00
    janxin
        1
    janxin  
       2017-11-07 09:02:55 +08:00
    你想把 celery 的异步动作变成同步监听?
    toono
        2
    toono  
    OP
       2017-11-07 09:10:05 +08:00
    @janxin 不是,我的想法是用 celery 启动线程去监听。如果造成了 celery 同步阻塞就不是我希望的效果了。

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

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

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

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

    所以 supervisor 另起一个进程是一个最简单,性能不会有风险的解决方案。 毕竟 Python 是 Python,不是 Java 后台开一堆线程池处理的,大家都在一个 JVM 干活的模式。
    toono
        19
    toono  
    OP
       2017-11-07 11:10:54 +08:00
    @pixstone 嗯😂,所以现在打算 supervisor + celery 来解决这个需求。多谢了~
    toono
        20
    toono  
    OP
       2017-11-07 11:12:23 +08:00
    @laoyur 我继续用 celery 去解决这个问题了,用 AppConfig 我觉得逻辑不是很清晰。
    wizardoz
        21
    wizardoz  
       2017-11-07 13:24:20 +08:00
    如果是需要同步监听的话还是建议单独开一个进程去监听,有数据以后 POST 到 django 或者通过消息队列。
    celery 的定时任务我觉得不适合这种场景。
    PS:在 wsgi.py 中可以直接开线程或者进程。但是如果是我的话还是会单独另起一个程序。
    clino
        22
    clino  
       2017-11-07 13:35:47 +08:00
    建议用 jenkins 之类的另外的工具去做
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5291 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 03:50 · PVG 11:50 · LAX 19:50 · JFK 22:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.