Question about standalone bokeh server implementation/websockets


I am running a standalone bokeh server, like explained in the github examples.

To get the plots from the server to my webpage, the front-end (VueJS) adds autoload script-tags to the page. For example when the user wants a scatterplot, a script tag of the following format is added to the page:
<script src="https://localhost:5006/scatter/autoload.js?bokeh-session-id=...&bokeh-autoload-element=...&bokeh-app-path=/scatter&bokeh-absolute-url=..."></script>

This injects the needed javascript and a websocket is opened to allow interactivity with the python session. Everything working as expected, but I noticed that all plots open a different websocket.
E.g plot1, 2 and 3 displayed -> 3 websockets (localhost:5006/plot1/ws, localhost:5006/plot2/ws ,localhost:5006/plot3/ws).
Is there any way to make them communicate over the same ws? I want to avoid having 100 websockets open per client when this project grows larger.

If you have remarks about my current implementation method, feel free to comment. This is the first time I use a bokeh server in a project.

Kind regards

I think you forgot to actually include the code. Can you edit the post?

forgot the backticks :slight_smile:

Is the bokeh-session-id query parameter always the same when a user requests a new plot?

Yes, each user has a unique session that is generated the first time they access the webpage.

I am afraid no one has ever asked about this usage scenario and it’s not one we had in mind (typically had in mind embedding one or two things in a page up front). So, there is nothing officially supported to share a websocket. In principle, I think something like this could be possible, but I also think it would require new development to support in a meaningful way, so a GitHub issue to describe the requirements in more detail would be an appropriate first step.

It’s potentially possible you could currently call Bokeh.embed.embed_items manually to re-use the same websocket, but I am not certain on that.

The WS should be reused if the session_id is the same:

It’s not that trivial to recreate what you’re doing, but it seems that you know your way around JS. Given the link to the code that I posted above, can you debug it and make sure that the session_id used there is the same? Or, in other words, that pull_session is called only once.

I would like to share some of my code, but there are so many parts involved that its hard to replicate.
I did some debugging on the pull_session function. It is only called once per websocket, as you would expect from looking at the code.

Example: 3 plots on page (2x plot1 and 1x plot2) -> only 2 websockets opened (ws::localhost:5006/plot1/ws and ws::localhost:5006/plot2/ws) each of them only calling pull_session once.

The problem is that the websockets don’t point to the same path (plot1 vs plot2).
I tried messing with the the _get_ws_url function ( by removing the app_path from the url. This makes that all generated ws-urls are always the same (/) :partying_face: (exactly what I want), the problem is that it throws a 404 :cry: (kinda expected) since there is no / route specified in my bokeh server.

I then quickly specified a / route, returning an empty document -> works, but plot1 and plot2 are not shown. It looks like there is something in bokeh that prevents this from working ( or my hacky solution just doesn’t work, since I don’t realy know how bokeh operates in the background)

I can maybe try to route all communication of the bokeh server over the root route and just work with parameters in the URL for the different plot types (localhost:5006/autoload.js?plot_type=plot1… instead of localhost:5006/plot1/autoload.js) :man_shrugging:

Thanks for your time to listen to someone that is trying to hack his way in bokeh by using it in a somewhat unconventinal way :smile:

Ah, so all these plots come from different documents? Well, then you’re out of luck because there’s 1-to-1 correspondence between documents, sessions, and WS connections on a single client.
A possible solution could be embedding these plots in a single document and then embedding separate roots when a user requests a different plot. I have no idea if that’s feasible in your case. Another solution is to not embed separate plots at all and instead just construct plots dynamically while embedding the whole document. That’s probably the most robust and simple approach.

I should have mentioned this earlier, but indeed all plots are different documents.
The reason for this was to make the bokeh server reusable for multilple applications. So if I have multiple applications in the future and they both want a scatterplot, I can just ask the bokeh server a scatterplot with the details for the data location in the request.

I also thought about only embedding 1 document and dynamically adding plots to the root of this document, but this would kinda make the bokeh server only usable for this 1 specifc application since different applications can require other dynamic plots to be available.

Is there any disadvangtage to embedding multiple documents on 1 page (other than the potential issue of having a lot of websockets open)?

Nothing that I can think of, apart from that overhead.