Panel server embedded in gunicorn/Flask hosted to cloud

I have a panel server embedded in a Flask app which is run via gunicorn with multiple worker processes. This works well when served on a either a Linux or Mac OSX system on an intranet, and I verified that I can also make it available externally for quick testing purposes.

I want to take the next step to deploy it to a cloud service like Heroku or the Google App Engine, but have been unsuccessful thus far. The application builds and deploys but the panel (or bokeh model) content does not render and the JavaScript console ultimately throws a connection-timeout-error.

The panel server deployment documentation gives sufficient detail to deploy a panel server application to Heroku, but the next piece is when this needs to be run through / embedded in a web framework like Flask that is ultimately serving additional content, managing user access to certain routes, etc.

As such, the panel(bokeh) server needs to be called via server_document() accessors as illustrated in the “official” bokeh Github repo example here: bokeh Flask gunicorn embed example.

Is there an example of such an implementation being successfully deployed to Heroku?

Thanks!

Mind filing an issue? We should add a few examples using flask with and without gunicorn to the repo.

Note that you can always use panel_object.server_doc(doc) to render to a bokeh document and then use the approach outlined in the bokeh example you linked.

Thanks @philippjfr

My app with Flask/gunicorn/panel works well currently. The problem I am facing is how to transition to a platform-as-a-service / cloud environment like Heroku or Google App Engine.

The code that works for me when hosting myself on a Linux or OSX computer does not work when trying on those services.

Update: This works on Heroku. There is more discussion on the Bokeh Discourse site for Topic 6199.

Here is a cut-and-paste of the main points. Some of the discussion is in the context of bokeh server, but since the panel server is the bokeh server, it all translates. In fact, the feasibility test case was using panel serve.

For others that have application architectures similar that embed a bokeh server in a gunicorn/Flask framework and want to deploy it to a platform as a service / cloud service, this can be done in Heroku using two dynos . After exhaustively exploring different mechanisms and helpful exchanges with the Heroku support team, getting everything to work in one dyno is not possible.

DETAILS

Flask-app which embeds the bokeh server on one dyno :

Create a python Flask app, e.g. a simple one as follows, and use the Heroku Procfile to run it via gunicorn , which is well documented on Heroku’s site.

from flask import Flask, render_template

from bokeh.client import pull_session
from bokeh.embed import server_session

BOKEH_URL = "https://<bokeh-app-name>.herokuapp.com/<bokeh-server-name>"

app = Flask(__name__)

@app.route('/', methods=['GET'])
def bkapp_page():
    with pull_session(url=PANEL_URL) as session:
        script = server_session(session_id=session.id, url=BOKEH_URL)
        return render_template("embed.html", script=script, template="Flask")

Bokeh server app which runs the bokeh server on second dyno :

Implement this as usual and create a Heroku Procfile that runs the server, e.g.

web: bokeh serve --address="0.0.0.0" --port=$PORT <bokeh-server-name> --allow-websocket-origin=<flask-app-name>.herokuapp.com

NB: The port argument is important b/c Heroku assigns the port that is used; you cannot choose it yourself.

NB: The quantities in <…> above should reflect the app names for your Heroku apps and the name of your bokeh server following the bokeh conventions if it is in single-file or directory format. Caveat, that only the single module bokeh-server-name.py case has been tested in determining the viability of the approach.

Thanks to @p-himik and @Bryan for the valuable help getting this to work!

2 Likes