Hi,
I’m working on an application that will be be serving plots to several users. I have a flask server that will start a new (embeded) bokeh server every time a new user connects to the page. I’ve drawn inspiration form: https://github.com/bokeh/bokeh/blob/2.3.0/examples/howto/server_embed/flask_embed.py
But in this case I want to have one bokeh server per application. The document created is different for each request, so I cannot use the same server. When a new user makes a GET request, a new bokeh server is spin up with a new application for that user.
I want to stop a Bokeh server (so I can reuse the port) whenever there are no active sessions.
I’m trying to achieve this with Tornado’s PeriodicCallback, but it doesn’t seem reliable. Sometimes it works, sometimes it keeps telling me the address is in use even though the server has been closed (maybe a race condition?). The get method (not shown) just starts a new bokeh server. The code looks like this:
from tornado.ioloop import PeriodicCallback
...
def bokeh_app(doc):
"""Bokeh application to be served by Bokeh server"""
doc.add_root(self.rendered_window)
def bk_worker():
ioloop=IOLoop()
server = Server(
{"/": bokeh_app}, io_loop=ioloop, allow_websocket_origin=["*"],
port=port, unused_session_lifetime_milliseconds=5000, check_unused_sessions_milliseconds=5000
)
def callback():
print("Periodic callback! at ", port)
print(server.get_sessions())
if not server.get_sessions():
server.stop()
ioloop.stop()
print(f"Stopped server at {port}")
pcallback = PeriodicCallback(callback, 15000)
pcallback.start()
server.start()
server.io_loop.start()
print(f"\nOpening Bokeh on http://localhost:{port}/")
print(
"If you are opening it in another machine, use the IP of your "
"desktop. You can use ifconfig to obtain it\n"
)
Thread(target=bk_worker).start()
Example output:
Periodic callback! at 5006
[<bokeh.server.session.ServerSession object at 0x7fe048165a90>]
Periodic callback! at 5006
[]
Stopped server at 5006
This works sometimes. But sometimes I get the following error when calling server()
after I’ve already stopped a previous server:
...
...pypi__tornado_py\
thon3_deps/tornado/netutil.py", line 174, in bind_sockets
sock.bind(sockaddr)
OSError: [Errno 98] Address already in use
Even though the server and io_loop() have been stopped. The server architecture page recommends not using Tornado’s IOLoop, but I don’t know how else to achieve what I want.
Any thoughts on this approach, or any other way I could stop a server when there are no active connections?