TypeError: 'module' 对象在使用 Flask-SocketIO、uWSGI+gevent 和 Nginx 时不可调用谁能帮我摆脱这个困境?

问题描述

我正在使用 Flask-SocketIO、带有 Gevent 的 uWsgiNginx 来开发 WebSocket 项目和对这个应用程序进行 dockerizing。我的应用程序的简单运行很好,但是当我使用 Gevent 添加 uWsgiNginx 时,它给了我一个错误,即 TypeError: 'module' object is not callable。我搜索了互联网,但没有得到有用的材料。我应该怎么做才能解决这个问题?我的烧瓶项目结构是:

vsoTS
│
├───app
│   │   views.py
│   │   __init__.py
│   ├───static
│   │    └───js
│   │    │      application.js
│   │    ├───templates
│   │    │      index.html
├───env
│  .dockerignore
│   app.ini
│   Dockerfile
│   requirements.txt
│   run.py

run.py

from gevent import monkey
monkey.patch_all()
from app import app
from app import socketio
print(type(socketio))
sock = socketio
if __name__ == "__main__":
    sock.run(host='0.0.0.0',port = 8084)

init.py

from flask import Flask
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app,logger=True,engineio_logger=True)
from app import views

Nginx.conf

server{    
    location /vsoTS {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://0.0.0.0:8084;
    }

    location /socket.io {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://0.0.0.0:8084/socket.io;
    }

}

uWsgi 配置位于 app.ini

[uwsgi]
gevent-monkey-patch = true
wsgi-file = run.py
callable = app
processes = 4
threads = 2
master = true
chmod-socket = 660
vacuum = true
mount = /=run.py
manage-script-name = true
die-on-term = true
py-call-osafterfork = true
need-app = true
enable-threads = true
strict = true
buffer-size=32768
gevent = 1000
http-websockets = true
http-socket = 0.0.0.0:8084
single-interpreter = true

在 Docker 容器中运行 Flask 应用程序后,它显示TypeError: 'module' object is not callable 详细日志如下。

vsots       | [uWsgi] getting INI configuration from app.ini
vsots       | *** Starting uWsgi 2.0.18 (64bit) on [Fri Jul 16 00:01:07 2021] ***
vsots       | compiled with version: 8.3.0 on 16 July 2021 00:00:39
vsots       | os: Linux-5.4.72-microsoft-standard-WSL2 #1 SMP Wed Oct 28 23:40:43 UTC 2020
vsots       | nodename: e1f246977cb5
vsots       | machine: x86_64
vsots       | clock source: unix
vsots       | pcre jit disabled
vsots       | detected number of cpu cores: 8
vsots       | current working directory: /app
vsots       | detected binary path: /usr/local/bin/uwsgi
vsots       | uWsgi running as root,you can use --uid/--gid/--chroot options
vsots       | *** WARNING: you are running uWsgi as root !!! (use the --uid flag) ***
vsots       | your memory page size is 4096 bytes
vsots       | detected max file descriptor number: 1048576
vsots       | - async cores set to 1000 - fd table size: 1048576
vsots       | lock engine: pthread robust mutexes
vsots       | thunder lock: disabled (you can enable it with --thunder-lock)
vsots       | uwsgi socket 0 bound to TCP address 0.0.0.0:8084 fd 3
vsots       | uWsgi running as root,you can use --uid/--gid/--chroot options
vsots       | *** WARNING: you are running uWsgi as root !!! (use the --uid flag) ***
vsots       | Python version: 3.9.5 (default,Jun 23 2021,15:01:51)  [GCC 8.3.0]
vsots       | Python main interpreter initialized at 0x5627d11d8810
vsots       | uWsgi running as root,you can use --uid/--gid/--chroot options
vsots       | *** WARNING: you are running uWsgi as root !!! (use the --uid flag) ***
vsots       | python threads support enabled
vsots       | your server socket listen backlog is limited to 100 connections
vsots       | your mercy for graceful operations on workers is 60 seconds
vsots       | mapped 703600 bytes (687 KB) for 8 cores
vsots       | *** Operational MODE: preforking+threaded ***
vsots       | Server initialized for eventlet.
vsots       | Server initialized for eventlet.
vsots       | <class 'flask_socketio.socketIO'>
vsots       | Wsgi app 0 (mountpoint='') ready in 0 seconds on interpreter 0x5627d11d8810 pid: 1 (default app)
vsots       | mounting run.py on /
vsots       | <class 'flask_socketio.socketIO'>
vsots       | Wsgi app 1 (mountpoint='/') ready in 0 seconds on interpreter 0x5627d11d8810 pid: 1
vsots       | uWsgi running as root,you can use --uid/--gid/--chroot options
vsots       | *** WARNING: you are running uWsgi as root !!! (use the --uid flag) *** 
vsots       | spawned uWsgi master process (pid: 1)
vsots       | spawned uWsgi worker 1 (pid: 8,cores: 2)
vsots       | spawned uWsgi worker 2 (pid: 9,cores: 2)
vsots       | *** running gevent loop engine [addr:0x5627cf7f1cf0] ***
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | spawned uWsgi worker 3 (pid: 10,cores: 2)
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | spawned uWsgi worker 4 (pid: 11,cores: 2)
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable
vsots       | TypeError: 'module' object is not callable

解决方法

我的代码的第一个问题是,我从原始 SocketIO 库中导入了 flask_socketio,并且我还在我的应用程序文件夹的 __init__.py 文件中导入了它。另一方面,我从 __init__.py 文件中的 run.py 导入 socketio 对象,因此从库中导入对象存在冲突,这就是为什么 TypeError: 'module' object is not callable 出现错误。下面给出了我的问题的解决方案。

init.py

from flask import Flask,render_template
from flask_socketio import SocketIO,emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
app.config['SERVER_NAME'] = None
socketio = SocketIO(app,cors_allowed_origins='*',async_mode=None,logger=True,engineio_logger=True)
from app import views

views.py

from app import app,render_template
from app import socketio,emit
import os
from random import random
from time import sleep
from threading import Thread,Event

run.py

from app import app

这是 flask-socketio 应用。为了运行应用程序,我在此之上使用了 gunicorn 而不是 uWSGI,它实际上作为 nginxflask_socketio 应用程序之间的桥梁,两者都在不同的 docker 容器中运行。 docker 容器中的flask socketio 应用程序的gunicorn 配置是,

CMD ["gunicorn","run:app","--bind","0.0.0.0:8084","--worker-class","eventlet","--workers","1","--log-level","DEBUG"]

我的代码的第二个问题是在单独的 docker 容器中运行的 nginx 的配置中。我是代理将 nginx 传递到 http 套接字地址,在我的情况下 proxy_pass http://0.0.0.0:8084;proxy_pass http://0.0.0.0:8084/socket.io; 这些传递是错误的。正确的配置是代理传递到您的烧瓶 socketio 所在的实际 docker 容器,并在其上使用 gunicorn 来运行此应用程序。就我而言,docker 容器 vsots8084 的端口上运行。 在 docker 容器中运行的 socket 应用程序的 nginx 配置是,

upstream vsoTS_http_node{
    server vsots:8084;
}
upstream vsoTS_socketio_nodes{
    ip_hash;
    server vsots:8084;
}
server {
    
    listen 80;
    server_name _;
    
    location /vsoTS {
        proxy_pass http://vsoTS_http_node;
    }
    location /vsoTS/socket.io {
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://vsoTS_socketio_node/socket.io;
    }

}

我通过 nginx 在 docker 容器中运行的 Flask 套接字应用程序的屏幕截图。 Screenshot of my running socket app