基于nginx+Gunicorn+flask-socketio的项目遇到的问题

项目目标,RESTfulAPI—>websocketAPI

1、关于部署和启动的坑

gunicorn.conf.py

import os
import stat

preload_app = True
bind = '0.0.0.0:5005'
bind = '0.0.0.0:5003'
backlog = 512
chdir = os.path.dirname(os.path.abspath(__file__))
worker_class = 'sync'
worker_class = "eventlet"
worker_connections = 600
backlog = 1024
workers = 1
threads = 8
loglevel = 'info'
access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'

if not os.path.exists('logs'):
    os.mkdir('logs')
    os.chmod('logs', stat.S_IRWXU+stat.S_IRWXG+stat.S_IRWXO)

accesslog = os.path.join(chdir, "logs/gunicorn_access.log")
errorlog = os.path.join(chdir, "logs/gunicorn_error.log")
flasklog = os.path.join(chdir, "logs/flask.log")

gunicorn+flask-socketio刚开始部署的时候总是出现connect不正常连接的情况,多个客户端连接的时候,出现冲突,表现为连接总数始终为1。出现这种情况的原因是gunicorn里的workers一定要设为1,否则就会出现冲突。

2、多线程/进程下socketio的emit功能失效,已解决

在app里添加了一个redis_listener的线程。

现在我想在这个线程里调用socketio的emit发送给前端消息,发现发不过去。

class Expire_listener():

    def __init__(self):
        self._value_lock = threading.Lock()
        # pass

    def start(self):
        sub_expire = redis_conn.pubsub()
        # 事件通过 Redis 的订阅与发布功能(pub/sub)来进行分发,故需要订阅 __keyevent@0__:expired,其中0表示dbindex
        sub_expire.psubscribe(**{'__keyevent@0__:expired': self.__expire_handler})
        logger.info("redis listen start...")
        def start_listen():
            with cur_app.app_context():

                for data in sub_expire.listen():
                    pass
        threading.Thread(target=start_listen).start()

这个线程用来监听一个计时工具,计时完成就触发update事件来刷新页面, 实现不用手动刷新界面就可以实时更新页面

这段代码是用while true实现的,也可以,就是很不好看,而且是伪实时,只是过了几秒钟自动刷新界面而已。

thread = None
@socketio.on("connect",namespace='/api/semaphore')
def connect():
    #global client_dict, flag_client_dict, users
    sid = request.sid
    logger.info({sid})
    #thread = socketio.start_background_task(target=sub, sid=sid)
    SingletonUserMgr().user_login(sid,thread)

class SingletonUserMgr(object):
    users = 0
    client_dict = {}
    flag_client_dict = {}

    def __init__(self):
        self.lock = threading.Lock()

    def user_login(self,sid,thread):
        with self.lock:

            self.users += 1
            self.flag_client_dict[sid] = True
            self.client_dict[sid] = thread
            if thread is None:
                thread = socketio.start_background_task(target=sub)

        print(self.flag_client_dict)
        print(f"connect 当前连接数 {self.users}")

def sub():
    while True:
        socketio.sleep(5)
        socketio.emit("update", data={'data':'update'},namespace='/api/semaphore')

使用消息队列,将两个线程进行通信

终于通过消息队列实现了两个线程之间的通信:

具体是在socketio初始化app的时候,将redis的消息队列作为参数传入了,然后就可以在redis_listener下进行emit消息了

基于nginx+Gunicorn+flask-socketio的项目遇到的问题
class DevelopmentConfig(BaseConfig):
    """ 开发配置 """
    #开发环境的semaphore token
    SEMAPHORE_TOKEN = "xxxxxxxxx"
    #前端容器用户名以及容器名称
    FRONTEND_USER = "xxxxx"
    FRONTEND_CONTAINER = "xxxxxv1.6"

    #Ansible Semaphore 的配置
    SEMAPHORE_IP = "10.18.0.12"
    SEMAPHORE_PORT = "3500"

    # redis配置
    REDIS_HOST = os.getenv('REDIS_HOST') or "10.xx.x.xx"
    REDIS_PORT = int(os.getenv('REDIS_PORT') or 6380)
    REDIS_PWD = '123456'
    # redis默认16个数据库
    REDIS_DB = 0
    REDIS_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'

        # mysql 配置
    MYSQL_USERNAME = os.getenv('MYSQL_USERNAME') or "root"
    MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD') or "123456"
    MYSQL_HOST = os.getenv('MYSQL_HOST') or "10.xx.x.xx"
    MYSQL_PORT = int(os.getenv('MYSQL_PORT') or 3307)
    MYSQL_DATABASE = os.getenv('MYSQL_DATABASE') or "book_portal"

    # mysql 数据库的配置信息
    SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}"

    SQLALCHEMY_TRACK_MODIFICATIONS = True
    SQLALCHEMY_ECHO = False

Original: https://blog.csdn.net/qq_42727362/article/details/126730608
Author: 很白很白的小白程序员
Title: 基于nginx+Gunicorn+flask-socketio的项目遇到的问题

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/744884/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球