Deploy Bokeh Server into production on IP address

Could downgrading Tornado fix the issue or could that mess up what’s being output by Bokeh?

I wouldn’t go that route. First, I’m not sure that’s a problem with that per se and second, Bokeh’s release notes have specific requirements for Tornado > 5.0/5.1 for releases 2.0/2.1, respectively.

Do you have any other suggestions? Sorry for being annoying, I just spent a month building a bokeh app that doesn’t work for multiple users at once so pretty stressed about this not working no matter what I try

Also, if the application was smaller, I believe the Flask app would work. it doesn’t seem to work because since it takes 5 mins to load. The one thread can only load one user at once. We then see one user taking 10 mins to load and by the time that even happens, the user gets bounced out because the bokeh Token expires. (Plus I need the multiple threads so that it doesn’t take 30 minutes when it is 6 users, which is realistically the most that would likely ever be on this tool)

1 Like

It is certainly not annoying, so don’t worry about that.

Stressful, I get it. Deep breaths. :slight_smile:

We know it works in principle with waitress, we just need to figure out if its due to the OS where you’re running the server, package versions, etc. And, for what it’s worth, I have a fairly complex self-hosted bokeh app of my own so there is no fundamental problem jumping from the illustrative examples to real scientific or visualization problems.

If you have the ability to set up a separate Python virtual environment with the latest versions of everything, you could try that to see if the waitress example works there. If not, it seems like the only difference from your setup and mine is the OS.

I’d also look seriously into profiling where things are taking so long in the startup. If it’s computations on the server is there anything that can be done to streamline? If it is pushing complex layouts or models or whatever to the client that’s another thing to investigate.

The problem is that, in production, I can’t use a newer version of bokeh because I ran into issues as in Select options update - #19 by _jm

I also don’t have the ability to set up a new virtual environment that easily because of corporate restrictions. And I can’t really speed it up that much, it’s pulling in and manipulating a couple of Gigs of data which is what makes it slow - I already have different runs for twice a day that do a lot of pre-computations to make these runs as fast as possible.

I’m not too worried about converting the simple example into my own app, I’m just worried about getting this simple example working.

Understood. I was just suggesting this as a temporary step to isolate if the problem is due to package versions or something more fundamental like running on Windows versus Linux (or OS X).

I understand, I just would have to upgrade and then downgrade again and if it was to work, I would just be in a terrible spot anyways because I’d be stuck between picking between two versions, each of which has issues for what I need to do.

That’s why I was looking at this:

But if I was to downgrade then bokeh would no longer work so really unsure about what to do here.

@Bryan I was wondering if you have any suggestions? I saw this thread (Tornado 5.0 compatibility · Issue #7308 · bokeh/bokeh · GitHub), unsure if this still applies here or is relevant. To summarize, the flask_gunicorn_embed.py example doesn’t work on Windows, even when using waitress instead of gunicorn as I get the issue:

RuntimeError: There is no current event loop in thread ‘Thread-1’.

This seems to have been addressed in bokeh in early 2018. See https://github.com/bokeh/bokeh/pull/7329.

And bokeh 2.0.2 that you’re using is circa Q1/Q2 2020.

For what it is worth, I have been working heavily in 2.0.2 for most of my development, which involves a lot of server deployment for multiple users. But, unfortunately, I’m doing everything in Linux and sometimes OS X.

Got it. I would of course just use multiple processes on the simple flask app but since I’m on windows I can’t. I can’t really upgrade or downgrade Bokeh as I said so I’m kind of stuck. I tried using asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
as well with the example but it didn’t work either.

@alexgrossman

A poor-man’s short-term solution might be to run your flask app six times, for example, with each set up for a separate port. Then you’ll have to do the bookkeeping/management of having your users only log in to their assigned port to avoid collisions. Would that work, albeit inelegantly, until you can investigate further?

So unfortunately I have zero experience with waitress (this is the first I’ve heard of it) and not much experience with Windows either. I’ve been variously asking the community for years if anyone would like to join the project to help anchor support on Windows but to date, no one has wanted to do that.

It’s hard to make specific suggestions without knowing what your actual constraints. E.g. can you run multiple instances of the server app on different ports, and then put them behind an Nginx load balancer so that all users see one URL?

I also don’t really have context for the statements about 5, 10 minutes to load. Are you doing 10 minutes of blocking work on every session creation? Can anything be done once up front e.g in a server lifecycle hook for server start?

I think so, definitely not permanently of course, but I do get the following error when trying to do so (when using same IP but different port):

OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

Me neither. I would be happy to run multiple instances of the app on different ports. I just personally have zero experience with this stuff (I studied AI so hadn’t even heard of a port until using Bokeh)

I would ignore the 5/10 minutes to load, as that is just a function of how much data needs to be opened. I’m not sure what a server lifecycle hook does or how I would use it but if it would reduce the load time to instantly then I guess that would potentially solve the issue with the flask app.

Sorry again for my lack of knowledge regarding these things. I really do enjoy using Bokeh, the only reason I’m so stressed about this right now is because I thought multiprocess deployment would be easy and I already presented this to my bosses and said I would get a link to the group soon but I can’t of course because of these issues.

Not sure why this is happening if you’re indeed using unique addresses/port combinations in the multiple instances being run. Perhaps another process is already using the ports you’ve chosen.

Look here for information on the error for Windows systems, and one of the responses shows how to check for processes using the ports that are causing the errors.

https://stackoverflow.com/questions/12362542/python-server-only-one-usage-of-each-socket-address-is-normally-permitted

See the Directory Format section of the bokeh server user’s guide.

If you include an app_hooks.py file with the functions named therein, bokeh will run those at the appropriate times of the server lifecycle.

on_server_loaded() gets run when you start the server on your Windows machine.

on_session_created() gets run when each client session starts.

So if you need to do any setup work that is common to all users you could do that upfront when the server is spooled up via on_server_loaded() and have it ready to go when users connect.

I believe it’s overlapping because it won’t run unless the port referenced in server_document is 5006 so it has to be that one for both right now

Would I be able to save everything to a dictionary that is then referenced when different users log on? I already precompute everything in a single dictionary as is. And no user is ever changing data within my app. Are there any examples of this?

Oh no. That definitely won’t work and it doesn’t need to be that way.

See the example I posted for the waittress embed problem. Not for the server implementation, but just for how the ports and addresses were handled. I used variables defined at the topmost scope of the file and then referenced them everywhere the IP addresses and ports are prescribed.