Fun issue today when I tried to scale up my FastAPI/Panel app combo; I have been following @Hoxbro 's advice to use the pattern … (Managing pull_session and server_session from FastAPI - #4 by sbi_vm)
pn.serve({'/app':lambda:CreateApp().gspec},)
… to ensure that separate sessions are kicked off per user (rather than a shared session).
I now have some app classes with arguments, so I thought I would be clever and do:
endpoint_dict = {f’app/{d}’:lambda:createApp(d=d,d2=d2).gspec for (d,d2) in instances_dict.items()}
Thinking that it would dynamically build out all the app endpoints, configured via the instances_dict.
The funny thing is, all the created endpoints shared the same input arguments! Seems like the lambda’s get stored with the last argument/expression values from the loop. I made a test case to see what’s happening in a simpler scenario:
import functools
def test_func(a,b):
return a*b
terms_dict = {1:2,
2:3,
3:4}
func_dict = {d:lambda:test_func(d,t) for (d,t) in terms_dict.items()}
print('testing output from lambda')
for i,f in func_dict.items():
print(f())
partials_dict = {d:functools.partial(test_func,d,t) for (d,t) in terms_dict.items()}
print('testing output from partials')
for i,p in partials_dict.items():
print(p())
testing output from lambda
12
12
12
testing output from partials
2
6
12
So seems like functools.partials might be the way to go for scaling out a dict of panel endpoints that each spawn new instances.
To get it to work I did something clunky like:
def get_new_layout(param1,param2):
app_inst = createApp(param1,param2)
return app_inst.layout
endpoint_dict = {f'app/{param1}':functools.partial(get_new_layout,param1,param2)() for (param1,param2) in APP_DICT.items()}
pn.serve(endpoint_dict,
port=5000,
allow_websocket_origin=["127.0.0.1:8000"],
address="127.0.0.1", show=False)
… and this works to kick off the different app instances with the different parameters, BUT I am back to the issue where it’s a shared session (2 users at same endpoint modify same instance).
I know @Marc does a lot with multiple-app configurations; is there an easier or more canonical way to “pass” arguments to the pn.serve endpoint dictionary?