Bokeh server embedded in gunicorn/Flask hosted to cloud

Great. Thanks for the update.

Regarding runtime.txt, I mentioned that bc it looked like Heroku was using Python 3.6 in some of the earlier logs of the thread.

I have a runtime.txt to explicitly specify a python version down to the major.minor.patch level. Here’s what I have for runtime.txt in one of my apps.

python-3.8.7

1 Like

That makes sense and does sound like a good practice too. :white_check_mark:

Hi,

Along the same lines… I now have a pretty happy couple of bokeh apps running on Azure essentially standalone:

bokeh serve \
--allow-websocket-origin="*" \
--index=/index.html \
--num-procs=${NUM_PROCS} \
--port 5006 \
ceoperformance \
electoralmaths

This web app is protected b y Azure app security (known MS logins only) which throws a MS login request if you try to hit the URL. All good but now I want to be a little more refined about what valid users can do (i.e. filter available stuff based on MS AAD user group) [apologies for getting all my terms wrong but hopefully relatively clear]

Now I have found what appears to be some useful guidance on how to pull user context into a Python/Flask app here which might be worthwhile if I can get a Flask/Bokeh link going in Azure in much the same way this does the job in Heroku.

So, I gather that

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

… is saying that the Bokeh server web app should ONLY accept connections from the Flask app URL (i.e a direct connection from a browser should fail) thus allowing me to ‘rely’ on the user credentials captured by the Azure/MS world and passed to the Flask app. Presumably those credentials (validated email) can be passed through to the Bokeh server as… not actually sure. Can they just be passed in the URL string? i.e. extend BOKEH_URL with [email protected]

Just asking before I open that pandoras box.

thanks

Hi,

Upfront I will say that it is possible to embed a bokeh server within a flask app and there are examples of this in the bokeh GitHub repository. See, for example, flask_gunicorn_embed.py in the examples here.

This is how I typically ran things during development or when hosting myself where I have control of the computer serving things. When I wanted to offload security, hardware management, etc. to a platform as a service like Heroku, constraints on websockets came into play, which compelled splitting the flask user registration and management, data upload via dropload, etc. provided by Flask and the engineering analysis and visualization via bokeh into two distinct apps.

To your specific questions …

Correct. In that serve execution command, bokeh will only allow connections from the URL explicitly provided in the command line and all other connections are refused.

And …

In my flask app, an authenticated user is connected to the bokeh server using bokeh’s pull_session method. You can see more in the examples referenced above, I believe, or read about it in the bokeh reference document here.

The pull_session method includes an arguments parameter, which is “dictionary of key/values to be passed as HTTP request arguments to Bokeh application code”. So this is a mechanism to append info to the URL via “?..” like you’ve correctly inferred.

That said, you are limited by how much info you can stuff into the HTTP URL request parameters. I typically only pass UI configuration flags and encoded keys via this mechanism rather than “naked” info like user-identifying quantities or sensitive data as a matter of practice.

In my applications, the Flask app typically involves uploading a user’s engineering data which might be sensitive (and in some cases many tens of megabytes). To handle this, the flask app creates a UUID, uses that as a key to store compressed versions of the data in a Redis in-memory data store (with a set expiration time after which the data disappears). The UUID key is then passed via the HTTP request arguments to bokeh, and the server uses that to pull the data out of the Redis in memory data store.

On Heroku, this is possible for two databases to have access to a Redis data store so its an efficient way for me to communicate large amounts of info and not have to expose things directly that I don’t want.

All that’s to say I think what you’ve outlined should be possible theoretically and in the way you’ve described … with the caveat that I don’t have any experience with Azure. But, you might want to consider slight modifications to the model initially outlined by passing references to sensitive information if that’s a concern or if you end up needing to pass several kilobytes or more such that you bump up against size limits of what can be passed via the HTTP URL request arguments mechanism.