Deployment Tips for Gunicorn

Hello there!

I was wondering if anyone has some prod deployment tips for a number of panel apps.

Our platform doesn’t run on containers currently so the expectation is we’d used Gunicorn with Supervisord on bare metal.

I know we have panel serve --num-procs=X and that we don’t necessarily need something like Gunicorn as tornado ships with a webserver.

But I see that the bokeh deployment is run using gunicorn [1] and also the docs for gunicorn mention that
running tornado standalone isn’t a recommended config [2].

Is there a similar command to bokeh.server.start:make_tornado(config_file='config.py') which I can run with panel?

Thanks for any help!

[1] bokeh server production deployment - #8 by Bryan - Community Support - Bokeh Discourse
[2] Design — Gunicorn 20.1.0 documentation

Hi @jamiec

A typical way to use gunicorn with a bokeh server is to leverage Flask to integrate the bokeh server sessions.

You can refer to the flask_gunicorn_embed.py example in the bokeh GitHub repository for details. Seeserver embed (flask_gunicorn_embed.py).

The readme there indicates running with

gunicorn -w 4 flask_gunicorn_embed:app

But, the gunicorn command can also be used as normal with a config file rather than specifying options like the number of workers (–w 4) on the command line.

The panel server is built on top of the bokeh server, so to get things to work under panel, only minimal changes are required. For the above-referenced flask_gunicorn_embed.py example, one way to accomplish this is to implement the following change (i.e. comment out the bokeh doc.add_root() statement and replace with panel layout and server_doc() statements; and obviously include the panel import).

#doc.add_root(column(slider, plot))
_col = pn.Column(slider, plot)
_col.server_doc(doc)

Note: There have been periodic recent regressions in panel that cause layouts to not render properly. See the following panel discourse topic for details.

1 Like

Thanks very much for the comprehensive response.

I was hoping I could do this without having to dip into flask and have to deal with that extra overhead as well as the risk with regressions as you point out.

I’ll keep an eye out on further developments in this area and will reply on this thread if I come across anything of note.

1 Like