I have a Flask python web app on uWSGI/nginx that works fine, except when I use pymongo, specifically when I initialize the MongoClient class. I get the following nginx error when I try to access the app while using pymongo:
019/02/19 21:58:13 [error] 16699#0: *5 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 127.0.0.1, server: example.com, request: "GET /api/test HTTP/1.1", upstream: "uwsgi://unix:/var/www/html/myapp/myapp.sock:”, host: “example.com”
My small test app:
from flask import Flask
from flask_cors import CORS
from bson.json_util import dumps
import pymongo
DEBUG = True
app = Flask(__name__)
app.config.from_object(__name__)
CORS(app)
client = pymongo.MongoClient() # This line
db = client.myapp
#app.route('/api/test')
def test():
item = db.items.find_one()
return item['name']
def create_app(app_name='MYAPP'):
return app
# if __name__ == '__main__':
# app.run(debug=True, threaded=True, host='0.0.0.0')
If I run this app from the command line (python app.py) it works fine accessing 0.0.0.0:5000/api/test, so I'm pretty sure it's just a uWSGI configuration issue. My first thought was to increase the uwsgi_read_timeout parameter in my nginx config file:
uwsgi_read_timeout 3600
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com www.example.com;
location /api {
include uwsgi_params;
uwsgi_read_timeout 3600;
uwsgi_pass unix:/var/www/html/myapp/myapp.sock;
}
location / {
root /var/www/html/myapp;
try_files $uri $uri/ /index.html;
}
#return 301 https://$server_name$request_uri;
}
But it had no apparent effect. My uWSGI app is running as a service, using the following config (myapp.ini):
[uwsgi]
module = wsgi:app
master = true
processes = 4
enable-threads = True
socket = /var/www/html/myapp/myapp.sock
chmod-socket = 660
vacuum = true
die-on-term = true
Again, everything seems to work fine except for when I try to initialize pymongo. Finally, my app's service file:
[Unit]
Description=uWSGI Python container server
After=network.target
[Service]
User=pi
Group=www-data
WorkingDirectory=/var/www/html/myapp
ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/apps-available/myapp.ini
[Install]
WantedBy=multi-user.target
I believe the issue is that you're forking and this causes issues with PyMongo.
PyMongo is thread safe but not Fork safe. Once you run the app in daemon mode you are forking the process. You'll have to create a MongoClient inside the app so that your threads can see it after the process has started.
You can try this(I didn't try this out, I normally wrap stuff like this in a class and do this in the init method):
def create_app(app_name='MYAPP'):
app.client = pymongo.MongoClient(connect=False) # this will prevent connecting until you need it.
app.db = app.client.myapp
return app
Read this: http://api.mongodb.com/python/current/faq.html#id3
Related
When I run the below code from a local Ubuntu machine, the socket connection is successfully established; however, when I deploy it to an Ubuntu server, it does not work.
This is the error message I received from Nginx.
- [28/Dec/2022:07:29:10 +0000] "GET /media HTTP/1.1" 404 153 "-" "Boost.Beast/266" "3.235.111.201"
Linux is running and I check the IP it is 200 and the application also is running.
The code is in the file aap.py
import json
import logging
from flask import Flask, request, jsonify
from flask_sockets import Sockets
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
import os
import logging
from logging.handlers import RotatingFileHandler
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
sockets = Sockets(app)
#app.route("/hello", methods=['GET', 'POST'])
def hello():
print("testing")
return jsonify({"message": "Success"})
#sockets.route('/test')
def test(ws):
print(f"*****Test****{ws}")
#sockets.route('/media')
def echo(ws):
print(f"Media WS: {ws}")
while True:
message = ws.receive()
packet = json.loads(message)
print(packet)
if __name__ == '__main__':
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler = RotatingFileHandler('log_data.log', maxBytes=10000, backupCount=2)
file_handler.setFormatter(formatter)
logging.basicConfig(handlers=[file_handler], level=logging.DEBUG)
logger = logging.getLogger('log_data.log')
app.logger.setLevel(logging.DEBUG)
server = pywsgi.WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler)
#server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
from the localhost, I run the command python3 app.py
Here is the screenshot of the terminal and socket connection test result.
My nginx config is in file /etc/nginx/sites-available/test-socket and the content is:
server {
listen 80;
server_name _;
access_log /var/log/nginx/access.log;
location / {
include proxy_params;
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://127.0.0.1:5000;
}
}
I am running one service file /etc/systemd/system/demo.service
[Unit]
Description=Gunicorn instance to serve testApp
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/root/test-socket
Environment="PATH=/root/test-socket/myenv/bin"
ExecStart=/root/test-socket/myenv/bin/gunicorn --worker-class eventlet -w1 --workers 3 --bind 127.0.0.1:5000 app:app
[Install]
WantedBy=multi-user.target
I'm desperately trying to figure out the issue of why I cannot deploy my flask application with uWSGI nginx and Ubuntu server.
Here is my error in nginx error log:
2019/05/12 09:00:19 [error] 10154#10154: *1 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 24.27.57.18, server: itinareport.tk, request: "POST /login HTTP/1.1", upstream: "uwsgi://unix:/home/pinchrep2/itinarep/itinarep.sock", host: "www.itinareport.tk", referrer: "http://www.itinareport.tk/login"
Upon having everything setup with flask uWSGI and nginx I'm able to put my domain name in and it takes me to my web page (Login Page). Upon attempting to login the page pauses for some time and then I receive the 504 Gateway Time-Out
Please advise me on what I should do. This is my first time ever deploying an application and it's been taking me about a week of trying different configurations. I should have you know that I have my flask application connecting to a database through ssh tunnel to another server. Not sure if that would cause this issue as well. Please help if possible or point me in the right direction.
Here is my server block configuration file
server{
listen 80;
server_name itinareport.tk www.itinareport.tk;
location / {
include uwsgi_params;
uwsgi_pass unix:/home/pinchrep2/itinarep/itinarep.sock;
}
Here is my service file:
[Unit]
Description=uWSGI instance to serve itinarep
After=network.target
[Service]
User=pinchrep2
Group=www-data
WorkingDirectory=/home/pinchrep2/itinarep
Environment="PATH=/home/pinchrep2/itinarep/it_venv/bin"
ExecStart=/home/pinchrep2/itinarep/it_venv/bin/uwsgi --ini itinarep.ini
[Install]
WantedBy=multi-user.target
Here is my ini file
[uwsgi]
module = wsgi:app
master = true
processes = 5
socket = itinarep.sock
chmod-socket = 660
vacuum = true
die-on-term=true
Sometimes when deploying a flask app with library like Keras and others they have some issue with threading in uWSGI.
You can change a few things in myproject.ini to make it work:
add these setting in myproject.ini
master = false <-------- this
processes = 1 <--------- and this
add cheaper = 0 to your myproject.ini
add lazy-apps = true to your myproject.ini
So now your myproject.ini file may look like:
[uwsgi]
module = wsgi:app
master = false <-------- this
processes = 1 <--------- and this
socket = myproject.sock
chmod-socket = 660
vacuum = true
die-on-term = true
cheaper = 0 <----------- also this, if option 1 is not enough or doesn't work
lazy-apps = true <------ in some case, this might help
I want to integrate Flask-SocketIO with my Flask project. My app is running behind a Nginx reverse proxy:
location /plivo_api{
rewrite ^/plivo_api(.*) /$1 break;
proxy_pass http://127.0.0.1:8090;
}
So I undestand all trafic received in the /plivo_api will be rewrited as "/" port 8090. This part work well.
The problem starts when I want to connect to the socket. Direct connection to socket has no problem.
# all those examples work
# from localhost
var socket = io.connect()
var socket = io.connect('http://localhost:8090/')
# running the app out of the reverse proxy
var socket = io.connect('http://my_server:8090/')
But throught Nginx I cannot connect
# Bad Gateway
var socket = io.connect('http://my_server/plivo_api')
Question is Do I'm missing something to connect to my socketio app or there's something extra to add to Nginx config ?
The flask app code with socketio integration looks like
# this code work well, the flask app and socket io
# problem must be in Ngin settings.
The flask app code with socketio integration looks like
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
HOST = '127.0.0.1'
PORT = 8090
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['DEBUG'] = True
app.config['SERVER_NAME'] = f'{HOST}:{PORT}'
socketio = SocketIO(app)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
socketio.run(app, port=PORT, host=HOST)
You need to create a special location block in nginx for the Socket.IO endpoint. You can't use a regular URL like you do for your HTTP routes.
The documentation has an example:
server {
listen 80;
server_name _;
location /socket.io {
include proxy_params;
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://127.0.0.1:5000/socket.io;
}
}
I am trying to deploy a Flask app on an Ubuntu server. I referenced this, this and this and found a lot of similar questions on SO, but I still can't figure it out.
I can run it manually from the source directory by doing uwsgi siti_uwsgi.ini and navigating to http://server_IP_address:8080/. But when I try uwsgi --socket 127.0.0.1:3031 --wsgi-file views.py --master --processes 4 --threads 2 and navigate to http://server_IP_address:3031, I get nothing.
If I go to siti.company.loc (the DNS name I set up), there is a standard Nginx 502 error page.
When I try to restart the supervisor process, it dies with a FATAL error:
can't find command "gunicorn"
What am I doing wrong? Let me know if I need to provide more info or background.
/webapps/patch/src/views.py (Flask app):
from flask import Flask, render_template, request, url_for, redirect
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r"/*": {'origins': '*'}})
#app.route('/')
def home():
return 'Hello'
#app.route('/site:<site>/date:<int:day>-<month>-<int:year>')
def application(site, month, day, year):
if request.method == 'GET':
# Recompile date from URL. todo: better way
dte = str(day) + "-" + str(month) + "-" + str(
print('about to run')
results = run_SITI(site, dte)
return results
def run_SITI(site, dte):
print('running SITI')
return render_template('results.html', site=site, dte=dte, results=None) # todo: Show results
if __name__ == '__main__':
app.run(debug=True)
/webapps/patch/siti_wsgi.ini (uWSGI ini):
[uwsgi]
http = :8008
chdir = /webapps/patch/src
wsgi-file = views.py
processes = 2
threads = 2
callable = app
/etc/nginx/sites-available/siti (Nginx config):
upstream flask_siti {
server 127.0.0.1:8008 fail_timeout=0;
}
server {
listen 80;
server_name siti.company.loc;
charset utf-8;
client_max_body_size 75M;
access_log /var/log/nginx/siti/access.log;
error_log /var/log/nginx/siti/error.log;
keepalive_timeout 5;
location /static {
alias /webapps/patch/static;
}
location /media {
alias /webapps/patch/media;
}
location / {
# checks for static file, if not found proxy to the app
try_files $uri #proxy_to_app;
}
location #proxy_to_app {
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://flask_siti;
}
}
/etc/supervisor/conf.d/siti.conf (Supervisor config):
[program:webapp_siti]
command=gunicorn -b views:app
directory=/webapps/patch/src
user=nobody
autostart=true
autorestart=true
redirect_stderr=true
/var/log/nginx/siti/error.log (Nginx error log):
2016/08/30 11:44:42 [error] 25524#0: *73 connect() failed (111: Connection refused) while connecting to upstream, $
2016/08/30 11:44:42 [error] 25524#0: *73 connect() failed (111: Connection refused) while connecting to upstream, $
2016/08/30 11:44:42 [error] 25524#0: *73 no live upstreams while connecting to upstream, client: 10.1.2.195, serve$
You have errors in nginx config:
Instead of:
upstream flask_siti {
server 127.0.0.1:8008 fail_timeout=0;
server {
...
try:
upstream flask_siti {
server 127.0.0.1:8080 fail_timeout=0;
}
server {
...
You must "activate" virtualenv in supervisor config. To do this, add following line to Your supervisor config:
environment=PATH="/webapps/patch/venv/bin",VIRTUAL_ENV="/webapps/patch/venv",PYTHONPATH="/webapps/patch/venv/lib/python:/webapps/patch/venv/lib/python/site-packages"
Was able to get it working with the following changes:
/etc/supervisor/conf.d/siti.conf (Supervisor config):
[program:webapp_siti]
command=/webapps/patch/venv/bin/gunicorn -b :8118 views:app # didn't use uwsgi.ini after all
directory=/webapps/patch/src
user=nobody
autostart=true
autorestart=true
redirect_stderr=true
/etc/nginx/sites-enabled/siti (Nginx config):
upstream flask_siti {
server 127.0.0.1:8118 fail_timeout=0; # changed ports because 8008 was already in use by something else
}
# snip ...
Turns out I had set up uWSGI to listen on port 8008. I also had an extra file in /etc/nginx/sites-enabled called siti.save that was preventing Nginx from reloading. I deleted it, reloaded/restarted Nginx, restarted Supervisor, and it worked.
I have my Python Flask web app hosted on nginx. While trying to execute a request it shows a timeout error in the nginx error log as shown below :
[error] 2084#0: *1 upstream timed out (110: Connection timed out)
while reading response header from upstream, client:
192.168.2.224, server: 192.168.2.131, request: "POST /execute HTTP/1.1", upstream: "uwsgi://unix:/hom
e/jay/PythonFlaskApp/app.sock", host: "192.168.2.131:9000", referrer:
"http://192.168.2.131:9000/"
If I try to run the app locally it works fine and responds fine.
Any one have any idea what might be wrong ?
the error found in browser console is :
Gateway Time-out
Here is the nginx config file:
server {
listen 9000;
server_name 192.168.2.131;
location / {
include uwsgi_params;
proxy_read_timeout 300;
uwsgi_pass unix:/home/jay/PythonFlaskApp/app.sock;
}
}
And here is the Python Fabric code that i trying to execute. i'm not sure if this is causing the issue, but any waz here is the code :
from fabric.api import *
#application.route("/execute",methods=['POST'])
def execute():
try:
machineInfo = request.json['info']
ip = machineInfo['ip']
username = machineInfo['username']
password = machineInfo['password']
command = machineInfo['command']
isRoot = machineInfo['isRoot']
env.host_string = username + '#' + ip
env.password = password
resp = ''
with settings(warn_only=True):
if isRoot:
resp = sudo(command)
else:
resp = run(command)
return jsonify(status='OK',message=resp)
except Exception, e:
print 'Error is ' + str(e)
return jsonify(status='ERROR',message=str(e))
I have a uWSGi config file for the web app and started it using an upstart script. Here is uwSGi conf file :
[uwsgi]
module = wsgi
master = true
processes = 5
socket = app.sock
chmod-socket = 660
vacuum = true
die-on-term = true
and here is upstart script
description "uWSGI server instance configured to serve Python Flask App"
start on runlevel [2345]
stop on runlevel [!2345]
setuid jay
setgid www-data
chdir /home/jay/PythonFlaskApp
exec uwsgi --ini app.ini
I have followed the below tutorial on running flask app on nginx
This is likely a problem with the Fabric task, not with Flask. Have you tried isolating / removing Fabric from the application, just for troubleshooting purposes? You could try stubbing out a value for resp, rather than actually executing the run/sudo commands in your function. I would bet that the app works just fine if you do that.
And so that would mean that you've got a problem with Fabric executing the command in question. First thing you should do is verify this by mocking up an example Fabfile on the production server using the info you're expecting in one of your requests, and then running it with fab -f <mock_fabfile.py>.
It's also worth noting that using with settings(warn_only=True): can result in suppression of error messages. I think that you should remove this, since you are in a troubleshooting scenario. From the docs on Managing Output:
warnings: Warning messages. These are often turned off when one expects a given operation to fail, such as when using grep to test existence of text in a file. If paired with setting env.warn_only to True, this can result in fully silent warnings when remote programs fail. As with aborts, this setting does not control actual warning behavior, only whether warning messages are printed or hidden.
As a third suggestion, you can get more info out of Fabric by using the show('debug') context manager, as well as enabling Paramiko's logging:
from fabric.api import env
from fabric.context_managers import show
# You can also enable Paramiko's logging like so:
import logging
logging.basicConfig(level=logging.DEBUG)
def my_task():
with show('debug'):
run('my command...')
The Fabric docs have some additional suggestions for troubleshooting: http://docs.fabfile.org/en/1.6/troubleshooting.html. (1.6 is an older/outdated version, but the concepts still apply.)