Questions about: Multi-User app + Access to sessions when using .servable with panel serve

First question is about getting access to sessions when using panel serve together with .servable() (and not using pn.serve()
when using pn.serve i can acess sessions through pn.state._sessions and i can create a callback to use pn.state.kill_all_servers()
but when using .servable and panel serve on the command line, the pn.state._sessions is empty and pn.state.kill_all_servers() does nothing…
How do I use kill_all_servers() when using servable()?
Some background about my question: My app currently uses .servable and i am trying to fix a memory issue, so as a temporary fix i wanted to implement a button on my app to kill all running servers, but it does not work because i cant access sessions.
Is there a way to see memory usage of each session separately?

Second question is about a multi-user app that i am trying to build.
I am getting a different server for each user, but they dont work at the same time… how do i get them to work at the same time?
see example below:
app.py looks like this:

%%

import panel as pn
import time
import threading
pn.extension()

%%

class MultiUserAppTest():

layout = pn.template.MaterialTemplate(
    title="MultiUserTest",
    sidebar_width=500,)
seconds_to_wait = 10
button = pn.widgets.Button(name=f"Wait {seconds_to_wait} seconds")
countdown_text = pn.pane.Markdown("123")

def __init__(self):
    watecher = self.button.param.watch(self.countdown, 'clicks')

def countdown(self, event=None):
    x = self.seconds_to_wait
    while x > 0:
        x -= 1
        print(x)
        time.sleep(1)
        self.countdown_text.object = str(x)

def get_layout(self):
    self.layout.main.append(pn.Column(self.button, self.countdown_text))
    return self.layout

def get_server(self):
    return self.get_layout().servable()

def user_instance():
def callback():
return
return MultiUserAppTest().get_server()

user_instance()

then i run panel “serve app.py” in the terminal

Thanks in advance for your help :slight_smile:

1 Like

Hi @alon-sht

Thanks for the question. Could you try updating the code section. It seems to not render nicely, so its not possible to easily copy-paste the code.

Please note you will need to put it inside a fenced code block

Hi, on my PC it is rendered well.
Here it is again:

import panel as pn
import time
import threading
pn.extension()

class MultiUserAppTest():

    layout = pn.template.MaterialTemplate(
        title="MultiUserTest",
        sidebar_width=500,)
    seconds_to_wait = 10
    button = pn.widgets.Button(name=f"Wait {seconds_to_wait} seconds")
    countdown_text = pn.pane.Markdown("123")

    def __init__(self):
        watecher = self.button.param.watch(self.countdown, 'clicks')

    def countdown(self, event=None):
        x = self.seconds_to_wait
        while x > 0:
            x -= 1
            print(x)
            time.sleep(1)
            self.countdown_text.object = str(x)

    def get_layout(self):
        self.layout.main.append(pn.Column(self.button, self.countdown_text))
        return self.layout

    def get_server(self):
        return self.get_layout().servable()


def user_instance():
    def callback():
        return
    return MultiUserAppTest().get_server()


user_instance()

1 Like

If I run the above nothing works, only when I move .servable after user_instance(). Then I get the countdown when clicking the button and can open multiple times running in each window.

Thats odd, both work for me in the same manner…
Are you able to run the countdown on both instances at the same time?

I’ll maybe try again but if I put x=user_instance(), then x.servable() I can open multiple times. Ok that part works, it also registers the click in all of them but something is queued or joined somehow, because the coutdown starts on instance 1, then instance 2 begins countdown at end of instance 1 and so on.

Yes, thats exactly the problem i am trying to fix. The click is registered in both of them, but it is queued.
I would like multiple users to be able to interact with the app at the same time.

You should move the widgets inside init.

This still doesn’t solve the problem…

Ok. As I see it, time.sleep is blocking the other webpage from updating. A way to fix this is to change the countdown method to an async function with asyncio.sleep. Another way is to wait for the new panel release and add --num-threads 2 to your panel serve command.

You should still move all the pn calls into __init__ to avoid shared states between different users.

async.sleep does seem to help here, but unfortunately i am having trouble implementing it in my actual code. I will have to learn further how to use it and implement it accordingly.

how about the first question?
any suggestions?

First question is about getting access to sessions when using panel serve together with .servable() (and not using pn.serve()
when using pn.serve i can acess sessions through pn.state._sessions and i can create a callback to use pn.state.kill_all_servers()
but when using .servable and panel serve on the command line, the pn.state._sessions is empty and pn.state.kill_all_servers() does nothing…
How do I use kill_all_servers() when using servable()?
Some background about my question: My app currently uses .servable and i am trying to fix a memory issue, so as a temporary fix i wanted to implement a button on my app to kill all running servers, but it does not work because i cant access sessions.
Is there a way to see memory usage of each session separately?