Am I using application dispatching in Flask correctly? - python-3.x

I am fairly new to Flask applications, but well versed in Python. I have recently begun making web applications instead of regular application and I'm trying to gather some of them on a single server. Enter "Application Dispatching".
I was hoping to be able to develop an app locally and then deploy it on the server using dispatching. This means that locally I will have a script that launches the Flask app (wsgi.py), which imports stuff in the application. Now, once I add it to the dispatcher, I import the new application. This means that before the wsgi.py was a script and now it is a module - all hell breaks loose.
dispatcher.py:
from flask import Flask
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.exceptions import NotFound
from app1 import app as app1
from app2 import app as app2
from app3 import app as app3
from app4 import app as app4
app = Flask(__name__)
app.wsgi_app = DispatcherMiddleware(NotFound(), {
"/app1": app1,
'/app2': app2,
'/app3': app3,
'/app4': app4,
})
if __name__ == "__main__":
app.run()
app1\__init__.py: (works like this, but merely a proof of concept / simple app)
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index_one():
return "Hi im 1"
if __name__ == "__main__":
app.run()
Both of these work - the dispatcher and the app1 can be run independently. Now, let's say I need to import a module to make app1 more functional:
from flask import Flask
import db
...
Since the dispatcher is in a parent directory, in order for it to work I need to do something like this:
from . import db
# or
from app1 import db
Now the application doesn't work independently anymore. I would like to avoid either having to refactor the application every time it needs to be deployed or adding a lot of boilerplate code like this:
if __name__ == "__main__":
import db
else:
from . import db
In any case this doesn't work when configuring the app with app.config.from_object("config.Config") as it can't be forced to be relative import (?) and otherwise can't find it without explicitly telling it which module it resides in.
From the tutorial, I got the sense that I could isolate the applications from each other:
Application dispatching is the process of combining multiple Flask
applications on the WSGI level. You can combine not only Flask
applications but any WSGI application. This would allow you to run a
Django and a Flask application in the same interpreter side by side if
you want. The usefulness of this depends on how the applications work
internally.
The fundamental difference from Large Applications as Packages is that
in this case you are running the same or different Flask applications
that are entirely isolated from each other. They run different
configurations and are dispatched on the WSGI level.
What am I doing wrong and can I get it working like I describe, by being able to launch the applications isolated or on the dispatcher, without changing my code or adding a bunch of unrelated boilerplate code to make it work?

I figured it out myself and indeed was using application dispatcher wrong. It will always integrate the different applications into one server instance.
Instead, I found out that using nginx could be used to forward to different server instances, thus completely separating the applications in each virtual environment.

Related

How do you host a multi-page Dash application on IIS?

I am trying to host a multi-page Dash application on IIS for internal use at work. I have been able to get single-page Dash applications, such as below to work.
from flask import Flask
import dash
import dash_html_components as html
from dash.dependencies import Input, Output
server=Flask(__name__)
app = dash.Dash(__name__, suppress_callback_exceptions=True, show_undo_redo=True, server=server)
app.layout = html.Div([])
#app.callback(Output('page-content', 'children'),
Input('url', 'pathname'))
def hello():
return "Single page dash app works but not multi-page"
if __name__ == "__main__":
app.run_server(host='0.0.0.0', port=84)
However, when I try to use it on multi-page dash applications, as described in the user manual here, it doesn't work correctly. I am able to host the application using Waitress, but would prefer something more stable and secure. IIS is how my company hosts other internal applications, so I was asked to host it that way. When attempting to use what I believe is the correct settings and handler mappings, I receive an error message on the page that simply says:
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
I believe that the issue is due to the fact that the flask application behind my Dash application is created in one script, and the entry point to the overall application is in another. I am not sure how to reconcile this, as the example page in the Dash documentation says that it must be this way.
So, how can I make this work?
cheers

is there a way to run flask on a thread?

in order to implement a system which exposes REST-api and run another functionality simultaneously, i tried to use flask like the flask like the following:
app = Flask(__name__)
app.run(threaded=True)
foo()
but foo function never starts.
I would to understand how to solve the problem or get an alternative option to implement it.
Thanks!
Going to the documentation for Flask.run() we see that the options provided (such as threaded) are forwarded to the underlying function werkzeug.run_simple(). The documentation for werkzeug.run_simple() says the following about the threaded parameter:
threaded – should the process handle each request in a separate thread?
This means that each REST call will be handled in a separate thread, but does not start the server in the background (which seems to be what you want). Instead, you can use the Process class from multiprocessing:
from flask import Flask
app = Flask(__name__)
from multiprocessing import Process
p = Process(target=app.run)
p.start()
foo()
This will start your flask app in the background, letting you run other functions after starting the app.

How can I deploy my API on IBM Cloud developed in Python and swagger?

I'm developing an API for our back-end, using python 3 and swagger + connexion (I just followed this great tutorial https://realpython.com/flask-connexion-rest-api/#using-connexion-to-add-a-rest-api-endpoint).
I was succesfully created my own API, when I run it locally the swagger ui perfectly appears (using this http://127.0.0.1:5000/api/ui/).
My problem is when I deploy it on IBM Cloud when I'm trying to access it, i have this error: 404 Not Found: Requested route does not exist).
Please see below my sample application code, my default python file.
# Sample flask app to connect to our backend
# __author__ = 'paulcaballero'
from flask import Flask, render_template
import data_connection as dc
import os
import connexion
from flask_restplus import Resource, Api
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#Create the application instance
app = connexion.App(__name__, specification_dir='./')
# Read the swagger.yml file to configure the endpoints
app.add_api('swagger.yml')
# If we're running in stand alone mode, run the application
port = os.getenv('PORT', '5000')
if __name__ == "__main__":
`app.run(host='0.0.0.0', port=int(port))
I want my default page to show all my endpoints.

Google Cloud Console - Flask - main.py vs package

OK, so I have been through some tutorials to get a flask app onto google cloud, which is fine.
I have also been through the flask tutorial to build a flaskr blog:
http://flask.pocoo.org/docs/1.0/tutorial/
It occurred to me that a sensible thing to do would be to create a database (MySQL in mycase) on google and then modify the code so that it uses that. This is fine and I can get it to work on my local machine.
However, now that I am coming to deploying this, I have hit a problem.
The google cloud tutorials tend to use a flask app that is initiated in a single file such as main.py, eg:
from flask import Flask, render_template
app = Flask(__name__)
....
The flask tutorial mentioned above uses a package and puts the code to create_app() in the __init__.py file and at present I cannot get this to start in the same way. (see sample code).
from flask import Flask
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev'
)
Are there some adjustments that I need to make to something like the app.yaml file to get it to recognise flask as the flaskr package or do I need to rewrite the whole thing so that it uses a main.py file ?
I feel that this is one of the points in time where I could really pick up a bad habit. What in general is the preferred way to write flask apps on google cloud ?
I am using the standard environment in google.
Thanks for your advice.
Mark
Since you have an application factory, you can create the app anywhere. Just create it in main.py, since this is what App Engine expects:
from my_package import create_app
app = create_app()

Flask + Bokeh Server on Azure Web App Service

I want to host my bokeh server app in Azure Web App Services. Following the example in flask_embed.py I created a minimal example with a bokeh server process running on localhost:5006 and serving it with server_document in a flask route. Locally, in my computer, it runs normally without any errors:
from threading import Thread
from bokeh.embed import server_document
from bokeh.server.server import Server
from bokeh.models.widgets import Select, Div
from bokeh.layouts import column
from flask import Flask
from flask import render_template
from tornado.ioloop import IOLoop
app = Flask(__name__)
# This is the bokeh page
def modify_doc(doc):
dropdown = Select(title="Cities", options=["New York", "Berlin"])
title_row = Div(text="Home Page")
main_layout = column([
title_row,
dropdown
])
doc.add_root(main_layout)
doc.title = "My bokeh server app"
# This is the subprocess serving the bokeh page
def bk_worker():
server = Server(
{'/bkapp': modify_doc},
io_loop=IOLoop(),
allow_websocket_origin=["*"],
)
server.start()
server.io_loop.start()
Thread(target=bk_worker).start()
# This is the flask route showing the bokeh page
#app.route("/", methods=["GET"])
def my_app():
script = server_document("http://localhost:5006/bkapp")
return render_template("embed.html", script=script, template="Flask")
However, when I push it to the Azure web app, the page is blank and by inspecting the page an error message is shown:
GET https://<my-azure-site>.azurewebsites.net:5006/bkapp/autoload.js?bokeh-autoload-element=0bfb1475-9ddb-4af5-9afe-f0c4a681d7aa&bokeh-app-path=/bkapp&bokeh-absolute-url=https://<my-azure-site>.azurewebsites.net:5006/bkapp net::ERR_CONNECTION_TIMED_OUT
It seems like I don't have access to the localhost of the remote Azure server. Actually, it's not yet clear to me if the bokeh server runs/is allowed to run at all. In the server_document function I have tried putting server_document("<my-azure-site>:5006/bkapp") but the problem remains the same.
Any help is appreciated.
This post is related to another question: Bokeh embedded in flask app in azure web app
I realize this is from a while ago, but I've spent many hours in the past several days figuring this out, so this is for future people:
The issue is that server_document() is just creating a <script> tag that gets embedded into a jinja2 template, where it executes.
Locally it's not an issue because your bokeh server is running on YOUR MACHINE'S localhost:5006. To demonstrate, you can see that you can navigate directly to localhost:5006/bkapp to see your bokeh document.
Once you're hosting it on Azure, server_document() is creating the exact same script that a browser will try to execute - that is, your browser is going to try to execute a <script> tag that references localhost:5006, except that there isn't anything running on localhost:5006 because your bokeh app is actually running on Azure's server now.
I'm not sure what the best way to do it is, but the essence of it is that you need server_document() to point to the bokeh server that's running remotely. To do this you'll need to make sure that {your_remote_bokeh_server}:5006 is publicly accessible.

Resources