Run Flask as threaded on IIS 7 - python

I am running a flask app using celery to offload long running process on a IIS 6.5 server and using python 2.7
The choice of the python 2.7, flask and IIS 7 server are imposed by the Company and cannot be changed.
The flask app works on IIS server (so the server set-up should be correct), except for the following.
I am struggling to find the good implementation to make flask works smoothly on the server.
I searched for similar questions on the site, but none helped so far.
When I am running the flask app on my pc, the application only performs as expected if I use OPTION A or OPTION B.
OPTION A:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello from FastCGI via IIS!"
if __name__ == "__main__":
app.run(threaded=True) # <--- This works
OPTION B:
If I wrap the flask app inside tornado, it works well as well:
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from myapp import app
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(5000)
IOLoop.instance().start()
OPTION C:
However if I run the flask app only with the default parameters, then it does not work the webserver is not returning the view that should be returned after a task has been offloaded to celery.
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello from FastCGI via IIS!"
if __name__ == "__main__":
app.run() # <--- Default App
Example of view working for OPTION A & B but not for OPTION C or on ISS:
Here below a stripped down example of a async task that is picked by celery. Note that I'm using Flask-Classy to generate the views, so the code is slightly different than the traditional routing in Flask.
class AnalysisView(FlaskView):
### Index page ---------------
def index(self):
return render_template('analysis.intro.html')
### Calculation process ------
def calculate(self, run_id):
t_id = task_create_id(run_id)
current_analysis = a_celery_function.apply_async(args=[x, y], task_id=t_id)
# Redirect to another view --> Not working when OPTION C or on ISS server
return redirect(url_for('AnalysisView:inprogress', run_id=run_id))
### Waiting page ---------------
def inprogress(self, run_id=run_id):
return render_template('analysis.inprogress.html')
My main problem is how can I use OPTION A (preferably, as it involves less change for me) or OPTION B to work together with IIS server?
Is there a way to tell flask to run with threaded=True during the Flask() initialization or via config settings?
Thanks in advance for you help.

Related

running multiple multi-route Flask applications

I have a flask app script that has multiple routes...
#app.py
def create_app(Tractor_id=0):
#app.route("/")
def index():
return render_template('index.html')
#app.route("/id")
def start():
return Tractor_id
#app.route("/stop")
def stop():
I'm trying to implement it multiple times with different parameters each time with the help of DispatcherMiddleware but I'm having trouble with it.
Here's the actual implementation:
# multiapp.py
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple
import start
T1 = start.create_app(Tractor_id='101')
T2 = start.create_app(Tractor_id='102')
# merge
application = DispatcherMiddleware(
None, {
'/{}'.format('T101'): T1,
'/{}'.format('T102'): T2
}
)
if __name__ == '__main__':
run_simple(
hostname='localhost',
port=5000,
application=application,
use_reloader=True,
use_debugger=True,
use_evalex=True)
In the index.html there are buttons that should redirect the user to the /id and /stop routes, but the do not work.
The general question would be, how to run multiple Flask applications which each have multiple routes within them?
I dont know DispatcherMiddleware.
But if you are trying to bind few flask servers, just pick for every process another port and it will work.
When you request them of course pay attention to port.
If you are struggling with actually making a multi route server, heres a good example.

Creating an API to execute a python script

I have a python script app.py in my local server (path=Users/soubhik.b/Desktop) that generates a report and mails it to certain receivers. Instead of scheduling this script on my localhost, i want to create an API which can be accessed by the receivers such that they would get the mail if they hit the API with say a certain id.
With the below code i can create an API to display a certain text. But, what do i modify to run the script through this?
Also if i want to place the script in a server instead of localhost, how do i configure the same?
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return ("hello world")
if __name__ == '__main__':
app.run(debug=True)
Python Version is 2.7
A good way to do this would be to put the script into a function, then import that function in your Flask API file and run it using that. For hosting on a web server you can use Python Anywhere if you are a beginner else heroku is also a good option.
If you are tying to achieve something using Python-Flask API than you can have a close look at this documentations and proceed further https://www.flaskapi.org/, http://flask.pocoo.org/docs/1.0/api/
Apart from these here are few basic examples and references you can refer for a quickstart :
1-https://programminghistorian.org/en/lessons/creating-apis-with-python-and-flask
2- https://flask-restful.readthedocs.io/en/latest/
3- https://realpython.com/flask-connexion-rest-api/
You could do something like this
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class ExecuteScript:
def printScript:
return "Hello World"
api.add_resource(ExecuteScript, '/printScript')
if __name__ == '__main__':
app.run(debug=True)

python flask return prior execution of reboot

for reasons I want to trigger the reboot of an raspberry pi using a REST api.
My REST api is coded in python flask like this:
from flask import Flask
from flask import jsonify
import subprocess
app = Flask(__name__)
#app.route('/api/reboot')
def reboot():
subprocess.call("/sbin/reboot")
return jsonify(triggered='reboot')
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")
the code is working perfectly fine. But due to its a reboot the return will not be send (because the system is rebooting obviously).
Is there a way to trigger the reboot some kind of async with a delay of a couple milliseconds, that allows to return some value (in my case just an custom 'ack') prior the actual reboot?
Try threading.Timer:
For example:
from flask import Flask
from flask import jsonify
import subprocess
import threading
app = Flask(__name__)
def _reboot():
subprocess.call("/sbin/reboot")
#app.route('/api/reboot')
def reboot():
t = threading.Timer(1, _reboot)
t.start()
return jsonify(triggered='reboot')
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0")

Why isn't Flask giving me an interactive debugger?

Here's a simple Flask app with a syntax error (it should be sys.version, not sys.version()
from flask import Flask, url_for, request, render_template
import sys
app = Flask(__name__)
app.config.from_object(__name__)
#app.route('/')
def index():
version = sys.version()
return "This is the index page. Python version info: {}".format(version)
if __name__ == '__main__':
app.run(debug=True)
When I run it locally and try to access http://localhost:5000, I get the nice Werkzeug debugger:
but when I run it on a remote server (Apache 2.4.17, mod_wsgi 4.4.21), I only get a generic 500 error page:
I've tried various things to make this work:
set app.debug = True right after app = Flask(__name__)
based on this link, I tried adding this code as well:
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(app, True)
but nothing seems to help.
I know that the debugger doesn't work in forked environments, but according to this link, the default mode for mod_wsgi is to not be forked. My Apache config is:
WSGIDaemonProcess flasktest user=david group=devgrp threads=1 python-path=/apps/www/80/wsgi-scripts/FlaskTest:/apps/.virtualenvs/flasktest/lib/python3.4/site-packages
So why can't I get the pretty debugger?
EDIT: Here's the modified file with my additions (that aren't working)
from flask import Flask
import sys
app = Flask(__name__)
app.config.from_object(__name__)
app.debug = True
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(app, True)
#app.route('/')
def index():
version = sys.version()
return "This is the index page. Python version info: {}".format(version)
if __name__ == '__main__':
app.run(debug=True)
To add WSGI middleware to a Flask app, wrap and replace the app's wsgi_app attribute. In the case of the debug middleware, set app.debug = True as well so that Flask doesn't convert exceptions to 500 responses.
app.debug = True
app.wsgi_app = DebuggedApplication(app.wsgi_app, evalex=True)
It is a security risk to run the debugger on a public server. Despite the recent change requiring a PIN before running code, the debugger may still be insecure in unforseen ways. Typically, you get information about errors in production by using logging. This answer is a good basic summary of how to set that up.
Your method would probably work if you had replaced app rather than calling it application. mod_wsgi was probably picking up app before application, so it was still running the original app. It's still recommended to wrap app.wsgi_app though.

Requests not able call multiple routes in same Flask application

I am not able to successfully use Python Requests to call a second route in the same application using Flask. I know that its best practice to call the function directly, but I need it to call using the URL using requests. For example:
from flask import Flask
import requests
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!" # This works
#app.route("/myrequest")
def myrequest():
#r = requests.get('http://www.stackoverflow.com', timeout=5).text # This works, but is external
#r = hello() # This works, but need requests to work
r = requests.get('http://127.0.0.1:5000/', timeout=5).text # This does NOT work - requests.exceptions.Timeout
return r
if __name__ == "__main__":
app.run(debug=True, port=5000)
Your code assumes that your app can handle multiple requests at once: the initial request, plus the request that is generated while the initial is being handled.
If you are running the development server like app.run(), it runs in a single thread by default; therefore, it can only handle one request at a time.
Use app.run(threaded=True) to enable multiple threads in the development server.
As of Flask 1.0 the development server is threaded by default.

Categories

Resources