gunicorn結合django啟動后台線程


 

preload 為True的情況下,會將輔助線程或者進程開在master里,加重master的負擔(master最好只是用來負責監聽worker進程)

 

django應用的gunicorn示例:只在主線程里開啟后台線程,worker里不啟動后台線程

gunicorn -w 5 --preload -b 127.0.0.1:8088 application_name.wsgi:application

wsgi.py文件:

"""
WSGI config for erebus project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application
from erebus.get_wsgi_application import get_wsgi_application
from whitenoise import WhiteNoise
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'erebus.settings')

application = get_wsgi_application()
application = WhiteNoise(application, root='./static/')
# application.add_files('/path/to/more/static/files', prefix='more-files/')

重寫的get_wsgi_application.py文件:

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    @Author      : xxxxx
    
    @Date        : 2019-02-27 19:26
    
    @Description : 本文件的作用描述
    
    @File        : get_wsgi_application.py 
"""

import django
from django.core.handlers.wsgi import WSGIHandler


def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Return a WSGI callable.

    Avoids making django.core.handlers.WSGIHandler a public API, in case the
    internal WSGI implementation changes or moves in the future.
    """
    django.setup(set_prefix=False)
    # 把主進程中的kafka consumer線程放入啟動過程中(即放入gunicorn的master進程中),
    # 以使用gunicorn的preload參數控制這些線程的啟動個數。
    from utils.kafka_consumer_daemon import start_kafka_consumer_daemon
    start_kafka_consumer_daemon()
    return WSGIHandler()

 

后台線程:

# 使用線程池子
def start_kafka_consumer_daemon():
    try:
        for _ in range(CONSUMER_THREAD_NUM):
            consumer = threading.Thread(target=consume_kafka)
            consumer.setDaemon(True)
            consumer.start()
    except Exception as e:
        logger.error(e)
        logger.error(traceback.format_exc())

 

 

 

 

配置參考:https://github.com/benoitc/gunicorn/blob/29f0394cdd381df176a3df3c25bb3fdd2486a173/examples/example_config.py

配置解讀:http://docs.gunicorn.org/en/stable/settings.html

 

 

Gunicorn+Flask中重復啟動后台線程問題

假設程序如下:

1 if __name__ == '__main__': 2 t = Thread(target=test) 3  t.start() 4 app.run(host='0.0.0.0',port=8080,debug=False)

      gunicorn在啟動過程只會從flask的app文件中取出app使用,並不會執行main函數,如果希望在gunicorn中仍舊能啟動后台線程並保證后台線程不因為gunicorn的子進程重復執行,有三種方式。

1.  使用gunicorn的preload參數。在worker進程被復制(派生)之前載入應用的代碼。這種方式,線程執行代碼需要寫在app文件的全局部分,利用預加載只執行一下。

2. 使用flask的app的鈎子函數before_first_request。在before_first_request中執行線程。但這種方式必須要有第一個請求才能觸發線程啟動。

3. 使用文件鎖。這種方式與第一種方式相同,需要把線程執行的代碼寫在app文件的全局部分。在第一個子進程啟動時創建文件並加鎖,在后續的子進程啟動時判斷鎖的狀態,如果有鎖則不執行。

   以上通過奇怪的操作啟動后台線程。但不推薦。可以考慮使用celery或者cron等方式實現需求。

 

 

參考:

1、https://www.jianshu.com/p/509985f98416

2、https://www.cnblogs.com/chenxianpao/p/9931483.html

3、

4、


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM