Bokeh Server Multiple users?

We’ve built our own report server using flask and bokeh servers!

It’s a neat little thing, completely deployed behind an apache reverse proxy, and everything works perfectly.

Except one little problem. The bokeh servers can only talk to one person at a time.

The Flask portion of the app is a platform that serves users to the bokeh servers while the bokeh servers are reports, themselves, executing queries against a database and displaying the results.

here:

How fun is that? Pretty fun.

So anyway, let’s say a user runs this report and it takes 30 seconds to fetch the data. While the query is running, nobody else can open the page.

We’re wondering what we should do about this. It would be great if we could tell bokeh server to be concurrent rather than spin up multiple instances of the same bokeh server.

Anyway, what would you guys suggest?

By the way here’s the route our flask app uses for a report, this should help you get a feel for how we have it setup. (notice we’re using bokeh.embed.server_document):

@app.route('/finance/gl-multiselect')
@verify_login
@verify_access
def finance__gl_multiselect():
    ''' bokeh for Gl multiselect '''
    resp = {
        'script': server_document(
            url='http://localhost:6010/gl_multiselect',
            arguments={...,}
        ),
        'template': 'Flask',
        'report_name': 'gl_multiselect',
    }
    return render_template('report/bokeh.html', **resp)

It’s definitely important to try and avoid long blocking work in the main thread of bokeh event handlers. The user’s guide describes how you can put long running tasks in threads, then update the Bokeh side when those tasks complete:

Bokeh server — Bokeh 3.3.2 Documentation

Bokeh server — Bokeh 3.3.2 Documentation

1 Like

What if there are global variables. Does the changing from one user affect the browsing of other users?

It all depends on what kind of global variables, how you use them, and how you talk to your users.
If it’s a regular variable, it will be visible in its current state to all users just the same.
If it’s a threading.local variable and you have exactly one thread per each user, then each user will have their own value.

In general, I would recommend just attaching your session-specific variables to to the session’s document. Python allows it just fine, and it’s the simplest approach with Bokeh.

It’s probably worth noting explicitly that:

  • Bokeh app code for a session is executed in new, individual modules just for that session. So “module globals” are unique per-session in the main app module.

  • Everything is in one process so standard Python module caching applies. If app code imports some outside module and mutates, every session will see that change if they also import it. (That’s just how modules work in python).

Bokeh app code for a session is executed in new, individual modules just for that session. So “module globals” are unique per-session in the main app module.

You don’t mean Python modules, do you? What in this case would an example of a “module global” be?

Yes, an actual Python ModuleType is created by the code runner:

And I jusst mean module global in the standard sense:

# main.py

# this is a module global
slider = Slider(....)

curoc().add_root(slider)

Every session gets its own module, with its own slider variable and value. And other sessions can’t access this, unless the app code (that you write) goes rooting around sys.modules (but if you deliberately write app code that does that, that’s on you)

Ah, but this would only work with bokeh serve then. Any embedding would fail since module globals would be shared. And the OP mentions having a Flask server.