Updating from threads, problems when reloading browser tab

Hi,

I was building an app with updating behavior copied from the example here: Running a Bokeh server — Bokeh 2.4.2 Documentation.

My app works fine, but after I try to reload the page in the browser I start getting NameErrors where the app can’t suddenly locate a function that was imported at the top of the module.

It seems like the example in the documentation exhibits the same behavior:

from functools import partial
from random import random
from threading import Thread
import time

from bokeh.models import ColumnDataSource
from bokeh.plotting import curdoc, figure

from tornado import gen

# only modify from a Bokeh session callback
source = ColumnDataSource(data=dict(x=[0], y=[0]))

# This is important! Save curdoc() to make sure all threads
# see the same document.
doc = curdoc()

@gen.coroutine
def update(x, y):
    source.stream(dict(x=[x], y=[y]))

def blocking_task():
    while True:
        # do some blocking computation
        time.sleep(0.1)
        x, y = random(), random()

        # but update the document from a callback
        doc.add_next_tick_callback(partial(update, x=x, y=y))

p = figure(x_range=[0, 1], y_range=[0,1])
l = p.circle(x='x', y='y', source=source)

doc.add_root(p)

thread = Thread(target=blocking_task)
thread.start()

Running the example with bokeh serve --show runs the app, but soon after reloading the page in the browser, the gives errors NameError: name 'random' is not defined.

I’m running Bokeh 2.4.1 and tried running it with Python versions 3.8.10 and 3.10.0.

How should this behavior be addressed?

I can’t reproduce any issue with Bokeh 2.4.1 and Python 3.9.6 on OSX. Page reloads work fine as expected with no errors reported in the console. More information and details are needed.

I was running the service on Ubuntu 20.04, browser is Chrome.

Here’s a more detailed log run with Python 3.8.10 and --log-level debug. I reloaded the browser twice after starting up the example code (saved it in file thread.py):

❯ bokeh serve --show thread.py --log-level debug
2021-11-17 19:37:12,506 Starting Bokeh server version 2.4.1 (running on Tornado 6.1)
2021-11-17 19:37:12,507 User authentication hooks NOT provided (default user enabled)
2021-11-17 19:37:12,507 These host origins can connect to the websocket: ['localhost:5006']
2021-11-17 19:37:12,507 Patterns are:
2021-11-17 19:37:12,508   [('/thread/?',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.doc_handler.DocHandler'>,
2021-11-17 19:37:12,508     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f8fda6b8d00>,
2021-11-17 19:37:12,508      'bokeh_websocket_path': '/thread/ws'}),
2021-11-17 19:37:12,508    ('/thread/ws',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.ws.WSHandler'>,
2021-11-17 19:37:12,508     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f8fda6b8d00>,
2021-11-17 19:37:12,508      'bokeh_websocket_path': '/thread/ws',
2021-11-17 19:37:12,508      'compression_level': None,
2021-11-17 19:37:12,508      'mem_level': None}),
2021-11-17 19:37:12,508    ('/thread/metadata',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.metadata_handler.MetadataHandler'>,
2021-11-17 19:37:12,508     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f8fda6b8d00>,
2021-11-17 19:37:12,508      'bokeh_websocket_path': '/thread/ws'}),
2021-11-17 19:37:12,508    ('/thread/autoload.js',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.autoload_js_handler.AutoloadJsHandler'>,
2021-11-17 19:37:12,508     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f8fda6b8d00>,
2021-11-17 19:37:12,508      'bokeh_websocket_path': '/thread/ws'}),
2021-11-17 19:37:12,508    ('/thread/static/(.*)',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.static_handler.StaticHandler'>,
2021-11-17 19:37:12,508     {}),
2021-11-17 19:37:12,508    ('/?',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.root_handler.RootHandler'>,
2021-11-17 19:37:12,508     {'applications': {'/thread': <bokeh.server.contexts.ApplicationContext object at 0x7f8fda6b8d00>},
2021-11-17 19:37:12,508      'index': None,
2021-11-17 19:37:12,508      'prefix': '',
2021-11-17 19:37:12,508      'use_redirect': True}),
2021-11-17 19:37:12,508    ('/static/extensions/(.*)',
2021-11-17 19:37:12,508     <class 'bokeh.server.views.multi_root_static_handler.MultiRootStaticHandler'>,
2021-11-17 19:37:12,509     {'root': {}}),
2021-11-17 19:37:12,509    ('/static/(.*)',
2021-11-17 19:37:12,509     <class 'bokeh.server.views.static_handler.StaticHandler'>)]
2021-11-17 19:37:12,512 Bokeh app running at: http://localhost:5006/thread
2021-11-17 19:37:12,512 Starting Bokeh server with process id: 868870
2021-11-17 19:37:14,250 Subprotocol header received
2021-11-17 19:37:14,251 WebSocket connection opened
2021-11-17 19:37:14,253 Receiver created for Protocol()
2021-11-17 19:37:14,253 ProtocolHandler created for Protocol()
2021-11-17 19:37:14,253 ServerConnection created
2021-11-17 19:37:14,265 Sending pull-doc-reply from session 'Bfh0eiH6mjH6hKZKj8JhzwVAynB7UiqFC30SKWThJbHj'
2021-11-17 19:37:18,276 WebSocket connection closed: code=1001, reason=None
2021-11-17 19:37:18,775 Subprotocol header received
2021-11-17 19:37:18,776 WebSocket connection opened
2021-11-17 19:37:18,777 Receiver created for Protocol()
2021-11-17 19:37:18,778 ProtocolHandler created for Protocol()
2021-11-17 19:37:18,778 ServerConnection created
2021-11-17 19:37:18,786 Sending pull-doc-reply from session 'zGzjcSSro3CRs7zabVf7nmwpKwlFv6BWFKV1dEyFW6vm'
2021-11-17 19:37:24,147 WebSocket connection closed: code=1001, reason=None
2021-11-17 19:37:24,638 Subprotocol header received
2021-11-17 19:37:24,639 WebSocket connection opened
2021-11-17 19:37:24,641 Receiver created for Protocol()
2021-11-17 19:37:24,642 ProtocolHandler created for Protocol()
2021-11-17 19:37:24,642 ServerConnection created
2021-11-17 19:37:24,655 Sending pull-doc-reply from session 'eugH9mcHyZtDFMYCedb1TyfHeLrmZOnPuWCMXLXZNnwx'
2021-11-17 19:37:27,513 [pid 868870] 1 clients connected
2021-11-17 19:37:27,513 [pid 868870]   /thread has 3 sessions with 2 unused
2021-11-17 19:37:42,513 [pid 868870] 1 clients connected
2021-11-17 19:37:42,513 [pid 868870]   /thread has 3 sessions with 2 unused
2021-11-17 19:37:46,513 Scheduling 2 sessions to discard
2021-11-17 19:37:46,514 Discarding session 'Bfh0eiH6mjH6hKZKj8JhzwVAynB7UiqFC30SKWThJbHj' last in use 28237.229090988636 milliseconds ago
2021-11-17 19:37:46,515 Deleting 1 modules for document <bokeh.document.document.Document object at 0x7f8fda682430>
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
2021-11-17 19:37:46,580 Discarding session 'zGzjcSSro3CRs7zabVf7nmwpKwlFv6BWFKV1dEyFW6vm' last in use 22432.686179995537 milliseconds ago
2021-11-17 19:37:46,580 Deleting 1 modules for document <bokeh.document.document.Document object at 0x7f8fda5282b0>
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self._target(*self._args, **self._kwargs)
  File "/home/max/omat/bqbokeh2/thread.py", line 26, in blocking_task
    x, y = random(), random()
NameError: name 'random' is not defined
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/home/max/omat/bqbokeh2/thread.py", line 29, in blocking_task
    doc.add_next_tick_callback(partial(update, x=x, y=y))
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/document.py", line 276, in add_next_tick_callback
    return self.callbacks.add_session_callback(cb, callback, one_shot=True)
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 188, in add_session_callback
    self.trigger_on_change(SessionCallbackAdded(doc, callback_obj))
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 378, in trigger_on_change
    invoke_with_curdoc(doc, invoke_callbacks)
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 408, in invoke_with_curdoc
    return f()
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 376, in invoke_callbacks
    for cb in self._change_callbacks.values():
AttributeError: 'DocumentCallbackManager' object has no attribute '_change_callbacks'

And here’s a more detailed log:

❯ bokeh serve --show thread.py --log-level trace
2021-11-17 19:47:29,206 Starting Bokeh server version 2.4.1 (running on Tornado 6.1)
2021-11-17 19:47:29,207 User authentication hooks NOT provided (default user enabled)
2021-11-17 19:47:29,207 These host origins can connect to the websocket: ['localhost:5006']
2021-11-17 19:47:29,207 Patterns are:
2021-11-17 19:47:29,208   [('/thread/?',
2021-11-17 19:47:29,208     <class 'bokeh.server.views.doc_handler.DocHandler'>,
2021-11-17 19:47:29,208     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f531d5bcd00>,
2021-11-17 19:47:29,208      'bokeh_websocket_path': '/thread/ws'}),
2021-11-17 19:47:29,208    ('/thread/ws',
2021-11-17 19:47:29,208     <class 'bokeh.server.views.ws.WSHandler'>,
2021-11-17 19:47:29,208     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f531d5bcd00>,
2021-11-17 19:47:29,208      'bokeh_websocket_path': '/thread/ws',
2021-11-17 19:47:29,208      'compression_level': None,
2021-11-17 19:47:29,208      'mem_level': None}),
2021-11-17 19:47:29,208    ('/thread/metadata',
2021-11-17 19:47:29,208     <class 'bokeh.server.views.metadata_handler.MetadataHandler'>,
2021-11-17 19:47:29,208     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f531d5bcd00>,
2021-11-17 19:47:29,208      'bokeh_websocket_path': '/thread/ws'}),
2021-11-17 19:47:29,208    ('/thread/autoload.js',
2021-11-17 19:47:29,208     <class 'bokeh.server.views.autoload_js_handler.AutoloadJsHandler'>,
2021-11-17 19:47:29,208     {'application_context': <bokeh.server.contexts.ApplicationContext object at 0x7f531d5bcd00>,
2021-11-17 19:47:29,208      'bokeh_websocket_path': '/thread/ws'}),
2021-11-17 19:47:29,208    ('/thread/static/(.*)',
2021-11-17 19:47:29,208     <class 'bokeh.server.views.static_handler.StaticHandler'>,
2021-11-17 19:47:29,208     {}),
2021-11-17 19:47:29,208    ('/?',
2021-11-17 19:47:29,208     <class 'bokeh.server.views.root_handler.RootHandler'>,
2021-11-17 19:47:29,208     {'applications': {'/thread': <bokeh.server.contexts.ApplicationContext object at 0x7f531d5bcd00>},
2021-11-17 19:47:29,208      'index': None,
2021-11-17 19:47:29,208      'prefix': '',
2021-11-17 19:47:29,208      'use_redirect': True}),
2021-11-17 19:47:29,209    ('/static/extensions/(.*)',
2021-11-17 19:47:29,209     <class 'bokeh.server.views.multi_root_static_handler.MultiRootStaticHandler'>,
2021-11-17 19:47:29,209     {'root': {}}),
2021-11-17 19:47:29,209    ('/static/(.*)',
2021-11-17 19:47:29,209     <class 'bokeh.server.views.static_handler.StaticHandler'>)]
2021-11-17 19:47:29,212 Bokeh app running at: http://localhost:5006/thread
2021-11-17 19:47:29,212 Starting Bokeh server with process id: 870430
2021-11-17 19:47:30,978 Subprotocol header received
2021-11-17 19:47:30,978 Supplied subprotocol headers: ['bokeh', 'eyJzZXNzaW9uX2lkIjogIlpCVEczY0FHb1E1T1k0eXI5bDBGaFAxeXJQQnpwMGhpSnp6a1FtM1pzYjlkIiwgInNlc3Npb25fZXhwaXJ5IjogMTYzNzE3NTE1MCwgIl9fYmtfX3psaWJfIjogImVOcGRVMTF2bXpBVV9Tc1dUMjJIQTRUdzFhaWEwbXhOb3liVnRDemFIcEFtWXk1Z3hkZ1VTSVphNWJfUGhtUmE4blk1NV9wY24tUExoMUVBU2FGdWpIdjBZVHpMcGxXRndTVWx2RkFmOTU1dC00YUpqTGtVQW1qTHBORDhEcURDaExNRGFHNERGTThMdkNXYWlvMkZsRGtITkM5cVdVSnNUQThQc1JGNXNlcU1qUjVrLV9JS25yN0tGczNRWTAxRWVxYWkyTGdReDJ1Wk1BNTZ4bWY3a3ZuR1Nadkp1aHptcjVqWWQ4UGhiWlhYeWgxZWlnYm92Z2I4SGQ3MjBMVGFyZUgwSFEzVWVKYUQ2SDJ2NVR2am5GamV5RVkzdnh4bmlub3gxSVgtYjM5eWkyWlZ4ZUVuSkMtc3RUdzNHTGstdW5sNV9yRmVtWWl6SGFBRjBKMjhQVm0zSWlVem12aHVPUElqdENFWnFkbnBsSjQ4b3hTcWZtb0xYV3NWYmNsTm92UVpKVHBtcTlQSXAtNGFMZm4wN2NFZVJTWXJTUTRXT2JEc1ZQNkJwRHFqbGNqTk8tdXVidzB2QkJxV0MwZ3hkTFFnSWdlVmRlSU9pdWRNbjZDbEJkNnd0czlhU0FHWHpGcW1BNk5tNTZTOVluV2dfUnM1bF9nWEdGWXJsWFJmNnJqX1JZQ19DaXBUSm5KTjUtLXNNbEVLbVhwU01GRlNfOWUzVWhmZUszdTZEd1JlUEpvZ1RtRmtERDh0VDI0ejFoZUJZdkYyMDlkOTRNc012eW96ZUUzVWZZWlZHWV9IRUUwQzhKMEpEZHd3OGNHR1pFd1NMM1J0TjBpSTQwSTRjYnhBYmROUktWQXBkd3o2WC1WNF9Bc25fX3JwIn0']
2021-11-17 19:47:30,979 WebSocket connection opened
2021-11-17 19:47:30,980 Receiver created for Protocol()
2021-11-17 19:47:30,980 ProtocolHandler created for Protocol()
2021-11-17 19:47:30,980 ServerConnection created
2021-11-17 19:47:30,985 Sending pull-doc-reply from session 'ZBTG3cAGoQ5OY4yr9l0FhP1yrPBzp0hiJzzkQm3Zsb9d'
2021-11-17 19:47:31,091 Patching attribute 'inner_width' of Figure(id='1003', ...) with 541
2021-11-17 19:47:31,092 Patching attribute 'inner_height' of Figure(id='1003', ...) with 573
2021-11-17 19:47:31,092 Patching attribute 'outer_width' of Figure(id='1003', ...) with 600
2021-11-17 19:47:31,092 Patching attribute 'outer_height' of Figure(id='1003', ...) with 600
2021-11-17 19:47:33,278 WebSocket connection closed: code=1001, reason=None
2021-11-17 19:47:33,787 Subprotocol header received
2021-11-17 19:47:33,787 Supplied subprotocol headers: ['bokeh', 'eyJzZXNzaW9uX2lkIjogInU2Zk9MNkVicmUycUVrcFViSVR1bWtpWUF5QlJpc0Q2ZEJJYUdsVkJGTlNnIiwgInNlc3Npb25fZXhwaXJ5IjogMTYzNzE3NTE1MywgIl9fYmtfX3psaWJfIjogImVOcGRVMkZ2MmpBUV9TdFdQclZkVEFKcFFsS0VKc3BXaWdyVk5JYTJENUVteDdra0ZvNmRCc09pVnZ6MzJRYW13WmZvY3VfOG51X2QtY09wZ09UUWJwMEg5T0U4eTYzU2djTWxKYnpTUHctaDcwZU9pNXlwRkFLb1lsSVlmQVBRWU1MWkhpeEdhQVZZVjZoV2NnUFhwTU9raExGdjBCVlFQSzN3bWhna2RXWlNsaHpRdEdwbERha3oybzlUSndsVFhaazZOc2wyOVZWNjlDb1ZtcURIbG9qOERDV3BjMEdPbHpKakhJekc1MHRaX0kwVFZjaTJQdW92bU5oMXg4UHJwbXgxNzNndXRrQjNMZUR2OExhRHJUSmVPSDFic1lVV1Qwb1ExcFdsZkdlY0V5X3MtZWptVjc4X1FwWU1kWEgwTzdxX1JaT200ZkFUc2hlbXZEQVk5b0lJM2J3OF8xZ3VYTVRaQnRBTTZFYmVubHIzRWszVHU0LUN1QmNsYUVVSzByTFRLYU04b1JRYXE2cWdVMTZsYXU0U3pjOG9NVVB3T3BQNTFGMW5hejU2R191OXhHVzFIb0JIOXF3NGhYOGdhODdaUnBUdW5YZG5TLU1MZ2kwckJlUVlPbG9SVVlMMk9ndU9qR2RQbjBEUkNxLVlzbDRMS2VBU1djcjhpR2p0a3FncjFCaHFaOVNfekgtQjQtTGxrdTVxWV9jX0NfQlhRV1hPUkduZzhwMDFMc3FoMENNRkYyWHRmM1VMZmVHZGJzX1VnY0N6UnhmRXlZeUM0YWY1cWR1QzJXQ29VYnhlMmRnYVBpX3dxMjRHTDRtLXozRlZNaHFIdzlpbllSelNoT2dQVFlMQklNdjlmalQwU1JSbGNSekVnNEZaeFlObW9GSnVHTmlIZERqOEJVTXZBX28ifQ']
2021-11-17 19:47:33,788 WebSocket connection opened
2021-11-17 19:47:33,790 Receiver created for Protocol()
2021-11-17 19:47:33,790 ProtocolHandler created for Protocol()
2021-11-17 19:47:33,791 ServerConnection created
2021-11-17 19:47:33,803 Sending pull-doc-reply from session 'u6fOL6Ebre2qEkpUbITumkiYAyBRisD6dBIaGlVBFNSg'
2021-11-17 19:47:33,912 Patching attribute 'inner_width' of Figure(id='1131', ...) with 541
2021-11-17 19:47:33,912 Patching attribute 'inner_height' of Figure(id='1131', ...) with 573
2021-11-17 19:47:33,913 Patching attribute 'outer_width' of Figure(id='1131', ...) with 600
2021-11-17 19:47:33,913 Patching attribute 'outer_height' of Figure(id='1131', ...) with 600
2021-11-17 19:47:36,732 WebSocket connection closed: code=1001, reason=None
2021-11-17 19:47:37,217 Subprotocol header received
2021-11-17 19:47:37,218 Supplied subprotocol headers: ['bokeh', 'eyJzZXNzaW9uX2lkIjogIk9uZmh5N1I2TXhCZ2dram1uckdKWDRqUjlKRWFucThMTUk4bXBzUDk1RzI5IiwgInNlc3Npb25fZXhwaXJ5IjogMTYzNzE3NTE1NiwgIl9fYmtfX3psaWJfIjogImVOcGRVOUZ1MmpBVV9SVXJUMjBYazZTQkVJclFSTmxLVWFHYXh0RDJFR2x5bkp2RXdySFR4TENvRmY4LTI4QTBlTHU1NV9nYzMzT2RENmNFa2tIVE9nX293M21XcmRLRnd5VWx2TlFmRHdQZmp4d1hPVE1wQkZERnBERDRGcURHaExNOVdJelFFckJtcUVaeUExZWt3NlNBaVdfUU5WQThLX0dHR0NSeDVsSVdITkNzYkdRRmlUUGVUeEpuTkVnME0zRnNrLTJxcV9iNFZTbzBSWThORWRrWkdpWE9oVGhleVpSeE1CNmZMMjN4TjA1VUxwdnE2TDlrWXRjZEQyX3FvdEd6NDRWb2dlNGF3Tl9oYlFldE1sazRnV1cwME9CcEFjS21zcEx2akhQaURYby11dmtWQkdOa3hWQVhSNy1qX2kyYTFqV0huNUMtTU9VTndtRXZqTkROeV9PUDFkSkZuRzBCellGdTVlMXBkRy1rWlhyOUtJeDcwUWl0U1U0YWRqcGxuS2VVUW0xZEZYVEtLMVhGWGFMMUdTVm1DVjVuT3AtNjYyN0Z4MjhUdnpkeVdhVVg0SkU5eTBfbEgwanJjN2NXaFh2bjNWbHFmQ0hRc2tKQWhxR2pKUkVGNkt6VDhLaDR6dlFKRkMzeG1pbWJ0WkFDTHBHVnpJNkk5aTZJdWtKTm9IWkh3V1hfQ3h3ZlhpYnByakp4XzRzQWZ4VlVaa3dVQmk3ZVdlMmlESEs5VW5CUjJ2ekhXLW9MN19SNGhnY0N6eDlkRUtjd2NvYWZGcWRwYzJhTG9VYnhabTFyR19naXg2OTZHTHdpLWo3SHB6S01ocFJHOTlBUGlKXzdjUnpra1JfMlIyRWUzVWNrQzlOLVJHbWNEMVA5bWc1YWdVcTVaV0JfcE1QaEwwazdCSUUifQ']
2021-11-17 19:47:37,219 WebSocket connection opened
2021-11-17 19:47:37,221 Receiver created for Protocol()
2021-11-17 19:47:37,221 ProtocolHandler created for Protocol()
2021-11-17 19:47:37,221 ServerConnection created
2021-11-17 19:47:37,235 Sending pull-doc-reply from session 'Onfhy7R6MxBggkjmnrGJX4jR9JEanq8LMI8mpsP95G29'
2021-11-17 19:47:37,336 Patching attribute 'inner_width' of Figure(id='1305', ...) with 541
2021-11-17 19:47:37,336 Patching attribute 'inner_height' of Figure(id='1305', ...) with 573
2021-11-17 19:47:37,336 Patching attribute 'outer_width' of Figure(id='1305', ...) with 600
2021-11-17 19:47:37,336 Patching attribute 'outer_height' of Figure(id='1305', ...) with 600
2021-11-17 19:47:44,213 Running stats log job
2021-11-17 19:47:44,213 [pid 870430] 1 clients connected
2021-11-17 19:47:44,214 [pid 870430]   /thread has 3 sessions with 2 unused
2021-11-17 19:47:46,213 Running session cleanup job
2021-11-17 19:47:59,214 Running stats log job
2021-11-17 19:47:59,214 [pid 870430] 1 clients connected
2021-11-17 19:47:59,214 [pid 870430]   /thread has 3 sessions with 2 unused
2021-11-17 19:48:03,213 Running session cleanup job
2021-11-17 19:48:03,213 Scheduling 2 sessions to discard
2021-11-17 19:48:03,213 Discarding session 'ZBTG3cAGoQ5OY4yr9l0FhP1yrPBzp0hiJzzkQm3Zsb9d' last in use 29935.273771047592 milliseconds ago
2021-11-17 19:48:03,214 Deleting 1 modules for document <bokeh.document.document.Document object at 0x7f531d586430>
2021-11-17 19:48:03,255 Session 'ZBTG3cAGoQ5OY4yr9l0FhP1yrPBzp0hiJzzkQm3Zsb9d' was successfully discarded
2021-11-17 19:48:03,255 Discarding session 'u6fOL6Ebre2qEkpUbITumkiYAyBRisD6dBIaGlVBFNSg' last in use 26522.838187992573 milliseconds ago
2021-11-17 19:48:03,256 Deleting 1 modules for document <bokeh.document.document.Document object at 0x7f531d427670>
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
Exception in thread Thread-1:
Traceback (most recent call last):
2021-11-17 19:48:03,294 Session 'u6fOL6Ebre2qEkpUbITumkiYAyBRisD6dBIaGlVBFNSg' was successfully discarded
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/home/max/omat/bqbokeh2/thread.py", line 29, in blocking_task
    doc.add_next_tick_callback(partial(update, x=x, y=y))
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/document.py", line 276, in add_next_tick_callback
    self._target(*self._args, **self._kwargs)
  File "/home/max/omat/bqbokeh2/thread.py", line 26, in blocking_task
    return self.callbacks.add_session_callback(cb, callback, one_shot=True)
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 188, in add_session_callback
    x, y = random(), random()
NameError: name 'random' is not defined
    self.trigger_on_change(SessionCallbackAdded(doc, callback_obj))
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 378, in trigger_on_change
    invoke_with_curdoc(doc, invoke_callbacks)
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 408, in invoke_with_curdoc
    return f()
  File "/home/max/omat/bqbokeh2/env/lib/python3.8/site-packages/bokeh/document/callbacks.py", line 376, in invoke_callbacks
    for cb in self._change_callbacks.values():
AttributeError: 'DocumentCallbackManager' object has no attribute '_change_callbacks'

Seems to be a race condition. Your thread is still running after the session is closed and the document and module for it have been destroyed, trying to execute code in contexts that no longer exist. As a blunt, immediate solution, catch the name error and exit the thread. Lifecycle hooks might offer a better way to clean up.

1 Like