I've been working on a new dev platform using nginx/gunicorn and Flask for my application.
Ops-wise, everything works fine - the issue I'm having is with debugging the Flask layer. When there's an error in my code, I just get a straight 500 error returned to the browser and nothing shows up on the console or in my logs.
I've tried many different configs/options.. I guess I must be missing something obvious.
My gunicorn.conf:
import os
bind = '127.0.0.1:8002'
workers = 3
backlog = 2048
worker_class = "sync"
debug = True
proc_name = 'gunicorn.proc'
pidfile = '/tmp/gunicorn.pid'
logfile = '/var/log/gunicorn/debug.log'
loglevel = 'debug'
An example of some Flask code that borks- testserver.py:
from flask import Flask
from flask import render_template_string
from werkzeug.contrib.fixers import ProxyFix
app = Flask(__name__)
#app.route('/')
def index():
n = 1/0
return "DIV/0 worked!"
And finally, the command to run the flask app in gunicorn:
gunicorn -c gunicorn.conf.py testserver:app
Thanks y'all
The accepted solution doesn't work for me.
Gunicorn is a pre-forking environment and apparently the Flask debugger doesn't work in a forking environment.
Attention
Even though the interactive debugger does not work in
forking environments (which makes it nearly impossible to use on
production servers) [...]
Even if you set app.debug = True, you will still only get an empty page with the message Internal Server Error if you run with gunicorn testserver:app. The best you can do with gunicorn is to run it with gunicorn --debug testserver:app. That gives you the trace in addition to the Internal Server Error message. However, this is just the same text trace that you see in the terminal and not the Flask debugger.
Adding the if __name__ ... section to the testserver.py and running python testserver.py to start the server in development gets you the Flask debugger. In other words, don't use gunicorn in development if you want the Flask debugger.
app = Flask(__name__)
app.config['DEBUG'] = True
if __name__ == '__main__':
app.run()
## Tip for Heroku users:
Personally I still like to use `foreman start`, instead of `python testserver.py` since [it sets up all the env variables for me](https://devcenter.heroku.com/articles/config-vars#using-foreman). To get this to work:
Contents of Procfile
web: bin/web
Contents of bin/web, file is relative to project root
#!/bin/sh
if [ "$FLASK_ENV" == "development" ]; then
python app.py
else
gunicorn app:app -w 3
fi
In development, create a .env file relative to project root with the following contents (docs here)
FLASK_ENV=development
DEBUG=True
Also, don't forget to change the app.config['DEBUG']... line in testserver.py to something that won't run Flask in debug mode in production.
app.config['DEBUG'] = os.environ.get('DEBUG', False)
The Flask config is entirely separate from gunicorn's. Following the Flask documentation on config files, a good solution would be change my source to this:
app = Flask(__name__)
app.config.from_pyfile('config.py')
And in config.py:
DEBUG = True
For Heroku users, there is a simpler solution than creating a bin/web script like suggested by Nick.
Instead of foreman start, just use foreman run python app.py if you want to debug your application in development.
I had similiar problem when running flask under gunicorn I didn't see stacktraces in browser (had to look at logs every time). Setting DEBUG, FLASK_DEBUG, or anything mentioned on this page didn't work. Finally I did this:
app = Flask(__name__)
app.config.from_object(settings_map[environment])
if environment == 'development':
from werkzeug.debug import DebuggedApplication
app_runtime = DebuggedApplication(app, evalex=False)
else:
app_runtime = app
Note evalex is disabled because interactive debbugging won't work with forking (gunicorn).
I used this:
gunicorn "swagger_server.__main__:app" -w 4 -b 0.0.0.0:8080
You cannot really run it with gunicorn and for example use the flask reload option upon code changes.
I've used following snippets in my api launchpoint:
app = Flask(__name__)
try:
if os.environ["yourapp_environment"] == "local":
run_as_local = True
# some other local configs e.g. paths
app.logger.info('Running server in local development mode!')
except KeyError as err:
if "yourapp_environment" in err.args:
run_as_local = False
# some other production configs e.g. paths
app.logger.info('No "yourapp_environment env" given so app running server in production mode!')
else:
raise
...
...
...
if __name__ == '__main__':
if run_as_local:
app.run(host='127.0.0.1', port='8058', debug=True)
else:
app.run(host='0.0.0.0')
For above solution you need to give export yourapp_environment = "local" in the console.
now I can run my local as python api.py and prod gunicorn --bind 0.0.0.0:8058 api:app
The else statement app.run() is not actually needed, but I keep it for reminding me about host, port etc.
Try setting the debug flag on the run command like so
gunicorn -c gunicorn.conf.py --debug testserver:app
and keep the DEBUG = True in your Flask application. There must be a reason why your debug option is not being applied from the config file but for now the above note should get you going.
Related
I am just getting started with Bottle. I have a sample app on GitHub. The main module app.py (in the Application folder) looks like below
"""
This script runs the application using a development server.
"""
import bottle
import os
import sys
# routes contains the HTTP handlers for our server and must be imported.
import routes
if '--debug' in sys.argv[1:] or 'SERVER_DEBUG' in os.environ:
# Debug mode will enable more verbose output in the console window.
# It must be set at the beginning of the script.
bottle.debug(True)
def wsgi_app():
"""Returns the application to make available through wfastcgi. This is used
when the site is published to Microsoft Azure."""
return bottle.default_app()
if __name__ == '__main__':
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'static').replace('\\', '/')
HOST = os.environ.get('SERVER_HOST', 'localhost')
try:
PORT = int(os.environ.get('SERVER_PORT', '5555'))
except ValueError:
PORT = 5555
#bottle.route('/static/<filepath:path>')
def server_static(filepath):
"""Handler for static files, used with the development server.
When running under a production server such as IIS or Apache,
the server should be configured to serve the static files."""
return bottle.static_file(filepath, root=STATIC_ROOT)
# Starts a local test server.
bottle.run(server='wsgiref', host=HOST, port=PORT)
The requirements.txt file has
bottle
gunicorn
as dependencies. I am using Python 3.7.2. After running pip install -r requirements.txt,
I ran python app.py. The server starts up and I can access the default page without error error
I tried running the server using gunicorn as below
gunicorn -w 2 -b 0.0.0.0:8080 app:wsgi_app
The server starts up fine, but when I access the default page, I get
Traceback (most recent call last):
File "/Users/<user>/Codebase/test-bottle/venv/lib/python3.8/site-packages/gunicorn/workers/sync.py", line 134, in handle
self.handle_request(listener, req, client, addr)
File "/Users/<user>/Codebase/test-bottle/venv/lib/python3.8/site-packages/gunicorn/workers/sync.py", line 175, in handle_request
respiter = self.wsgi(environ, resp.start_response)
TypeError: wsgi_app() takes 0 positional arguments but 2 were given
Please let me know what I've done wrong.
You can run the app without modifying the code using the “application factory” pattern (as stated in the gunicorn documentation):
gunicorn -w 2 -b 0.0.0.0:8080 'app:wsgi_app()'
Please note, that your page will not display fully, thought. The static links, e.g. css, will not load, since you are not defining any routes in your code in this case:
def wsgi_app():
"""Returns the application to make available through wfastcgi. This is used
when the site is published to Microsoft Azure."""
return bottle.default_app()
have you tried the following ?
from bottle import route, run, static_file
#route('/')
def index():
return '<h1>Hello Bottle!</h1>'
#bottle.route('/static/<filepath:path>')
#route("/static//<filepath:re:.*")
def server_static(filepath):
"""Handler for static files, used with the development server.
When running under a production server such as IIS or Apache,
the server should be configured to serve the static files."""
return bottle.static_file(filepath, root=STATIC_ROOT)
if __name__ == "__main__":
run(host='localhost', port=5555)
app = bottle.default_app()
then in a console :
gunicorn -w 4 your_app_name:app
I have set up my first Flask project with PyCharm and this is my app.py file:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'TEST'
if __name__ == '__main__':
app.run(debug=True)
I want to run my project in debug mode so that I do not have to restart the server every time something changes. I provide the app.run function with a debug=True parameter, but this does not seem to change the debug flag. The application does start however and I do see "TEST" on the page, but this is with the debug flag set to False.
I also tried to directly change my env variable with os.environ["FLASK_DEBUG"] = "True", but this did not affect the flag also.
Any advice?
If you're using PyCharm, in Run/Debug config you can pass FLASK_DEBUG variable.
Try to set it to "1", not to "True".
Run your flask app in command line instead of PyCharm. python3 app.py
I'm running a cherrypy based app on an openshift gear. Recently I've been getting a "503 service temporarily unavailable" error whenever I try to go to the site. Inspecting the logs, I see I'm getting an ImportError where I try to import CherryPy. This is strange - CherryPy is listed as a dependency in my requirements.txt and used to be imported just fine. I double checked to make sure I'm getting the right path to the openshift activate_this.py and it seems to be correct. I'm not quite sure where to look next; any help would be appreciated. Thanks!
The failed import is at line 14 of app.py:
import os
import files
virtenv = os.path.join(os.environ['OPENSHIFT_PYTHON_DIR'], 'virtenv')
virtualenv = os.path.join(virtenv, 'bin', 'activate_this.py')
conf = os.path.join(files.get_root(), "conf", "server.conf")
try:
execfile(virtualenv, dict(__file__=virtualenv))
print virtualenv
except IOError:
pass
import cherrypy
import wsgi
def mount():
def CORS():
cherrypy.response.headers["Access-Control-Allow-Origin"] = os.environ['OPENSHIFT_APP_DNS']
cherrypy.config.update({"tools.staticdir.root": files.get_root()})
cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
cherrypy.tree.mount(wsgi.application(), "/", conf)
def start():
cherrypy.engine.start()
def end():
cherrypy.engine.exit()
if __name__ == "__main__":
mount()
start()
UPDATE
I eventually saw (when pushing to the openshift repo using git bash CLI) that the dependency installation from requirements.txt was failing with some exceptions I haven't bothered to look into yet. It then goes on to try to install dependencies in setup.py, and that works just fine.
Regarding the port in use issue...I have no idea. I changed my startup from tree.mount and engine.start to quickstart, and everything worked when I pushed to openshift. Just for kicks (and because I need it to run my tests), I switched back to cherrypy.tree.mount, pushed it, and it worked just fine.
Go figure.
I use the app.py entry point for Openshift. Here are several examples on how I start my server using the pyramid framework on Openshift. I use waitress as the server but I have also used the cherrypy wsgi server. Just comment out the code you don't want.
app.py
#Openshift entry point
import os
from pyramid.paster import get_app
from pyramid.paster import get_appsettings
if __name__ == '__main__':
here = os.path.dirname(os.path.abspath(__file__))
if 'OPENSHIFT_APP_NAME' in os.environ: #are we on OPENSHIFT?
ip = os.environ['OPENSHIFT_PYTHON_IP']
port = int(os.environ['OPENSHIFT_PYTHON_PORT'])
config = os.path.join(here, 'production.ini')
else:
ip = '0.0.0.0' #localhost
port = 6543
config = os.path.join(here, 'development.ini')
app = get_app(config, 'main') #find 'main' method in __init__.py. That is our wsgi app
settings = get_appsettings(config, 'main') #don't really need this but is an example on how to get settings from the '.ini' files
# Waitress (remember to include the waitress server in "install_requires" in the setup.py)
from waitress import serve
print("Starting Waitress.")
serve(app, host=ip, port=port, threads=50)
# Cherrypy server (remember to include the cherrypy server in "install_requires" in the setup.py)
# from cherrypy import wsgiserver
# print("Starting Cherrypy Server on http://{0}:{1}".format(ip, port))
# server = wsgiserver.CherryPyWSGIServer((ip, port), app, server_name='Server')
# server.start()
#Simple Server
# from wsgiref.simple_server import make_server
# print("Starting Simple Server on http://{0}:{1}".format(ip, port))
# server = make_server(ip, port, app)
# server.serve_forever()
#Running 'production.ini' method manually. I find this method the least compatible with Openshift since you can't
#easily start/stop/restart your app with the 'rhc' commands. Mabye somebody can suggest a better way :)
# #Don't forget to set the Host IP in 'production.ini'. Use 8080 for the port for Openshift
# You will need to use the 'pre_build' action hook(pkill python) so it stops the existing running instance of the server on OS
# You also will have to set up another custom action hook so rhc app-restart, stop works.
# See Openshifts Origin User's Guide ( I have not tried this yet)
#Method #1
# print('Running pserve production.ini')
# os.system("pserve production.ini &")
#Method #2
#import subprocess
#subprocess.Popen(['pserve', 'production.ini &'])
I have below setup in my Python application
server.py
from bots.flask_app import app
from bots.flask_app.api import api
from bots.flask_app.public import public
from bots import db
from bots.commons.helpers.flask.json.serializer import make_alternative_encoder
from flask_debugtoolbar import DebugToolbarExtension
import logging
import bots.commons.managers.configuration as ConfigurationManager
logger = logging.getLogger()
#######
# Public functions
#######
def setup_db_and_app():
# Flask application bootstrap
config = ConfigurationManager.get_flask_rest_config()
app.config.update(config)
logger.debug('Flask configuration object: %s', app.config)
# MongoDB connection initialization
db.init_app(app)
# Debug toolbar enabled only if Flask in debug mode
if ConfigurationManager.get_raw_flask_rest_config()['flask']['debug']:
DebugToolbarExtension(app)
# Replace the serializer with the custom one (for ObjectId and DateTime serialization)
app.json_encoder = make_alternative_encoder(app.json_encoder)
# Register the components
app.register_blueprint(api)
app.register_blueprint(public)
def start_server():
setup_db_and_app()
logger.debug('Registered routes: %s', app.url_map)
app.run(host='0.0.0.0')
main.py
import bots.flask_app.server as FlaskApp
import bots.commons.managers.log as LogManager
# Logging initialization
LogManager.init_logging()
# Defined in server.py
FlaskApp.start_server()
I am trying to see whether this applicator can bed served by uwsgi as below
uwsgi --socket 0.0.0.0:8080 --protocol=http -w main
The output is as follows
INFO:werkzeug: * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
INFO:werkzeug: * Restarting with stat
unable to load configuration from uwsgi
My questions
1. Where can I find the configurations which are causing this issue?
2. Can main.py be defined as a callable and used as a parameter for -w?
This is an app which is already written by someone and I am trying make this application served through uwsgi.
Any suggestions would be helpful
Thanks
I had the 'unable to load configuration from uwsgi' error too. According to flask uwsgi docs:
Please make sure in advance that any app.run() calls you might have in your application file are inside an if __name__ == '__main__': block or moved to a separate file. Just make sure it’s not called because this will always start a local WSGI server which we do not want if we deploy that application to uWSGI.
I move app.run() to if __name__ == '__main__':, and the problem solved. Maybe you can try to put FlaskApp.start_server() under if __name__ == '__main__':.
I'm a bit late to the party, I've encountered this error when I forgot to remove debug=True from app.run(). It makes sense that you can't run the debug server with uwsgi.
I'm trying to figure out how to run a web service on heroku using flask and JSONRPC.
I would like to get to a point where, from my desktop I can do:
from flask_jsonrpc.proxy import ServiceProxy
service = ServiceProxy('http://<myapp>.heroku.com/api')
result = service.App.index()
print result
looking at heroku logs I can see :
2014-07-05T13:18:42.910030+00:00 app[web.1]: 2014-07-05 13:18:42 [2] [INFO] Listening at: http://0.0.0.0:21040 (2)
and trying using that port with :
service = ServiceProxy('http://<myapp>.heroku.com:21020/api')
still doesn't make it work (it seems hanging)
But when I run this through foreman, though, I can happy access it and seems working fine.
but when I try with the deployed application I get:
ValueError: No JSON object could be decoded
This is the application (not much I know , but is just to see how heroku works)
import os
from flask import Flask
from flask_jsonrpc import JSONRPC
app = Flask(__name__)
jsonrpc = JSONRPC(app, '/api', enable_web_browsable_api=True)
#jsonrpc.method('App.index')
def index():
return u'Welcome to Flask JSON-RPC'
if __name__ == '__main__':
port = int(os.environ.get("PORT", 5000))
app.run(host='0.0.0.0', debug=True, port=port)
this is the content of my Procfile:
web: gunicorn run:app -p $PORT
Am I missing something obvious here ?
Cheers.
L.
p.S
accessing http://.heroku.com/api/browse
from within the through foreman and the deployed app, it seems working fine.
[edit]
solved :
yes I was missing something.... looking better a the log I noticed the host which was :
host=<myapp>.herokuapp.com
instead of
.heroku.com
Changing the address to the correct one, it all seems working fine.
http://.herokuapp.com/api
All sorted , see original post.
Sorry for the noise.