How to use pn.state.on_session_destroyed

Hi

I am trying to use pn.state.on_session_destroyed to clean up. And i received an error of “RuntimeError: Could not add session destroyed callback since no document to attach it to could be found.”

Do we have any example about how to the on_session_destroyed?

Any help will be gratefully

Kind regards
Victor

1 Like

Hi @CongTang

Could you provide more detail of what you are doing like a minimum, reproducible example?

1 Like

Hi Marc

I am trying to user on_session_destroyed to remove the name.

Please see the code below:

import panel as pn
import pandas as pd
import numpy as np
import string
import random
 
pn.extension(sizing_mode='stretch_width',comms = 'vscode',notifications=True) 

if 'user_infor' not in pn.state.cache:
    pn.state.cache['user_infor']  = pd.DataFrame(columns = ['Name','Role']).set_index('Name')
player_name = ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))
pn.state.cache['user_infor'].loc[player_name] = 'game_role'


table = pn.pane.DataFrame(
    pn.state.cache['user_infor']
)

def update():
    table.object = pn.state.cache['user_infor']
    
game_page_cb = pn.state.add_periodic_callback(update, 5000,start  =True,timeout = 60000)

def user_logout():
    pn.state.cache['user_infor'].drop(player_name)

pn.state.on_session_destroyed(user_logout)

app = pn.Column(table)  

app.servable();

and get an error:ValueError: Callback functions must have signature func(session_context), got func()

Any suggestion will be greatful :grinning:

Kind regards
Cong

Hi @CongTang

As I read the error message your update callback signature needs to change to def update(session_context).

If I change to that, I can get the below working.

import panel as pn
import pandas as pd
import numpy as np
import string
import random
 
pn.extension(sizing_mode='stretch_width',comms = 'vscode',notifications=True) 

if 'user_infor' not in pn.state.cache:
    pn.state.cache['user_infor']  = pd.DataFrame(columns = ['Name','Role']).set_index('Name')
player_name = ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))
pn.state.cache['user_infor'].loc[player_name] = 'game_role'


table = pn.pane.DataFrame(
    pn.state.cache['user_infor']
)

def update():
    table.object = pn.state.cache['user_infor']
    
game_page_cb = pn.state.add_periodic_callback(update, 5000,start  =True,timeout = 60000)

def user_logout(sessionContext):
    print(sessionContext)
    pn.state.cache['user_infor'].drop(player_name)
    print("dropped")

pn.state.on_session_destroyed(user_logout)

app = pn.Column(table)  

app.servable()
$ panel serve 'scripts\specify_value.py' --autoreload
2023-03-24 05:48:37,500 Starting Bokeh server version 2.4.3 (running on Tornado 6.2)
2023-03-24 05:48:37,501 User authentication hooks NOT provided (default user enabled)
2023-03-24 05:48:37,503 Bokeh app running at: http://localhost:5006/specify_value
2023-03-24 05:48:37,503 Starting Bokeh server with process id: 34328
2023-03-24 05:48:41,577 WebSocket connection opened
2023-03-24 05:48:41,578 ServerConnection created
2023-03-24 05:48:41,578 404 GET /favicon.ico (::1) 0.00ms
2023-03-24 05:48:50,253 WebSocket connection closed: code=1001, reason=None
2023-03-24 05:48:59,854 WebSocket connection opened
2023-03-24 05:48:59,855 ServerConnection created
2023-03-24 05:49:10,740 WebSocket connection closed: code=1001, reason=None
<bokeh.server.contexts.BokehSessionContext object at 0x0000019377B37F70>
dropped
1 Like

I’ve made a PR to describe the required callback signature. Please take a look @CongTang and let me know if this improvement would have solved your issue up front.

Describe on_session_destroyed callback signature by MarcSkovMadsen · Pull Request #4555 · holoviz/panel (github.com)

Thanks.

1 Like

Hi Marc

Really thanks for your help. That work pretty well. :grinning:

Kind regards
Victor

1 Like

Hi Marc

Just noticed an issue(not too sure if it is a mechanism or a bug).

The pn.state.on_session_destroyed is only working with the --atuoreload , otherwise it will end up with

<bokeh.server.contexts.BokehSessionContext object at 0x0000025CA72F3BE0>
2023-03-26 18:41:37,316 DocumentLifeCycleHandler on_session_destroyed callback <function user_logout at 0x0000025CA72EBA30> failed with following error: name 'pn' is not defined

Kind regards
Vcitor

1 Like

It looks like a bug to me. Could you report it on github @CongTang ?

As a workaround you can try adding

import panel as pn

to your user_logout callback.

1 Like

Sure. I will report it to GitHub.

Yes, if I import it, it will work. But it will not unable to process some parameters of the original program.

and i would see it is not a serious bug as it still works with --atuoreload

Thanks for your answer and support. :grinning:

Kind regards
Victor

1 Like

It happens as sessions are being unloaded from memory. I’ve encountered the same bug numerous times:

[BUG] background thread stops when session is destroyed, leading to weird errors - Panel - HoloViz Discourse

'Exception' is not defined - lol

pn.state.on_session_destroyed callback also doesn’t work when you use lifecycle hooks in a separate file (even though it’s in the state’s callbacks). However, the on_session_destroyed callback does get called from within the app_hooks.py file :man_shrugging:

Extra FYI:
The session unloading seems to happen more aggressively when using --num-threads
This is actually a nice bug (feature? :grin: ) as you can get around memory leaks. Even better if you periodically restart your cluster workers to release memory back to the OS:
image

Haven’t had issues with memory leaks since.

Ah, btw - this also makes watcher callbacks fail. Can only let them fail silently as sessions are being unloaded.

image

2 Likes