Async io_loop lock process?

I am a newbie in bokeh, so my question should be stupid…
But when I try to test the following bokeh example:

I only replace Server(...,numprocs=4) by numprocs=1 .
And I had a print('finish') as a last line of code in this example after the ‘server.io_loop.start()’.
When I close the web browser, I obtain the following message:
###!!! [Parent][MessageChannel] Error: (msgtype=0x160080,name=PBrowser::Msg_Destroy) Closed channel: cannot send/recv
And my python process seems to be listening on default port 5006 ‘for_ever’, without printing the message ‘finish’ as I was waiting by the print last command line.

Is the error message could explain such behaviour ? and I need to solve this point.
Or is-it the expected behaviour? (i.e. python process listening for_ever)
In this last case, how can I integrate more python code after the server.io_loop.start() to be execute after I close the web browser? (need to use a thread in way to manage bokeh server for example ?)

Starting a Tornado IOLoop (or in general, any event loop fro any async/io library) is a completely blocking operation that will run exclusively until it is terminated. If you want to run code after it has started, there are only two options:

  • use threads

  • have the code to run be previously set up as callback on the event loop to run later.

Thanks a lot Bryan for these explanations!
So, I need to start bokeh server in a thread instance, or using a run_at_timeout_callback(timeout_callback=XXXmseconds) to solve my problem?
Sorry, but I have done several tests without any success.
Could you help me with more examples details ?

@john-pasglop I’m sorry I don’t have anything to share offhand. It’s probably better to come at this from the other direction, i.e. you share some actual code that you have tried.

Following your advice, I try to use a thread to manage my bokeh server, taking care about the following point

in the following example :

   from bokeh.models import ColumnDataSource
   from bokeh.plotting import figure
   from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature
   from bokeh.server.server import Server
   import threading
   import asyncio
   from tornado.platform.asyncio import AnyThreadEventLoopPolicy
   def bkapp(doc):
       df = sea_surface_temperature.copy()
       source = ColumnDataSource(data=df)
       plot = figure(x_axis_type='datetime', y_range=(0, 25), y_axis_label='Temperature (Celsius)',
                     title="Sea Surface Temperature at 43.18, -70.43")
       plot.line('time', 'temperature', source=source)
       doc.add_root(plot)
   def launch_server(myport) :
       asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy())
       server = Server({'/': bkapp}, num_procs=1,port=myport)
       server.start()
       server.io_loop.add_callback(server.show, "/")
       server.io_loop.start()
   print (' Create thread  ')
   bokeh_thread = threading.Thread(target=launch_server,args=(0,))
   print (' Start  thread  ')
   bokeh_thread.start()
   print(' End test')
   input('?')

I try to understand why the last line input(’?’) doesn’t seems to work
I just try to launch the bokeh server without being ‘lock() for_ever’ in way to realize another things in my main program

@john-pasglop please always format code samples, either by putting triple backtick ``` fences around the block, or by using the <\> button in the editor. You can go back and edit your post above with the pencil icon at the bottom.

You’ll have to be more specific about “doesn’t seems to work”. When I run the code above, with Bokeh 1.4 and Python 3.7, the input call does work, and I am prompted to input text.

I need to terminate the python process using ‘Ctrl+c’
It’s like the thread in charge of the bokeh server can’t be killed when the main process stops its execution.

There is no official way to “kill” a thread in Python, so this is expected behaviour, completely independent of Bokeh. If you want to daemonize the thread, so that the main process will exit immediately, you can do:

bokeh_thread = threading.Thread(target=launch_server,args=(0,), daemon=True)

Otherwise, there is some discussion of different ways to set up a thread to terminate itself when you want in this SO question:

Thanks a lot for the solution!