Issue
I am using Flask-SocketIO, uWSGI with Gevent, and Nginx for the development of the WebSocket project and dockerizing this app as well. The simple run of my app is good but when I add uWSGI with Gevent, and Nginx it gives me an error which is TypeError: 'module' object is not callable. I searched the internet but nothing get helpful material. What should I do to solve this problem? My flask project structure is:
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 configuration resides in 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
After running the flask app in a Docker container, it shows me the TypeError: 'module' object is not callable
detailed logs are given below.
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
Solution
The first problem with my code was, I was importing SocketIO
from the original flask_socketio
library and I also imported this in the __init__.py
file of my app folder. on the other hand, I was importing socketio object from __init__.py
in the run.py
file so there was a conflict of importing the objects from libraries, that's why TypeError: 'module' object is not callable error raised. Solution to my problem is given bellow.
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
this is the flask-socketio
app. to run app I used gunicorn
instead of uWSGI
on top of this which actually working as a bridge between nginx
and flask_socketio
apps, both are running in different docker containers.
gunicorn configuration for flask socketio app in a docker container is,
CMD ["gunicorn", "run:app", "--bind", "0.0.0.0:8084", "--worker-class", "eventlet", "--workers", "1", "--log-level", "DEBUG"]
The second problem with my code was in the configuration of nginx which is running in a separate docker container. I was proxy passing nginx to http socket address which was in my case proxy_pass http://0.0.0.0:8084;
and proxy_pass http://0.0.0.0:8084/socket.io;
these passes was wrong. The correct configuration for this is proxy pass to actually docker container in which your flask socketio resides and on top of it gunicorn is used to run this app. in my case, docker container vsots
running on the port of 8084
.
nginx configuration for socket app running in docker container is,
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;
}
}
Screenshot of my flask socket app running in docker container through nginx.
Answered By - Raza Ali
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.