On my main form, I’ve placed a LogOut button. This is intended to encourage people to knowingly log out (apply good application hygiene), thus immediately closing the session, instead of simply closing the browser, which may leave them logged in for as long as half an hour.
However, this creates a problem. Sub-forms can be nested arbitrarily deep, and any of them can make an anvil.server.call(). As many calls as they want, actually. So an app may be busy, doing all sorts of things that require a logged-in user, for seconds or even minutes at a time.
Meanwhile, the LogOut button is there, enabled, and if clicked, the browser will insert its actions in among all of the other the pending effects, somewhere. The result: any pending actions taken after the logout are likely to fail.
Have I made a design error? Or is there a way for the LogOut button to know that there are no other pending events it could screw up?
Edit 1: Yes, I’ve reviewed Disabling user interaction while server callable runs . The problem is not just server calls. LogOut should be available only when the app’s UI is idle.
Hi @p.colbert, I just find out the way to fix it today, not sure it is suitable for your case
Before making any server calls, disable to the button and enable it right after that. The sever call last 30s and any authentication check should be done during that time. There is no check in the background task
1 Like
Hi @p.colbert,
What I’d build here is a counter - “how many pieces of code, across my whole app, are doing something right now?”. This is what we do (eg) in Anvil’s saving spinner. I’d put it in a Module, so you could do:
import BusyTracker
# ... then, when you want to do something...
try:
BusyTracker.mark_working()
#...do the thing...
finally:
BusyTracker.mark_done()
Then one place (the BusyTracker module) can keep a count of how many tasks are working, and only show “log out” when they’re done.
For extra bonus points, you could create a Python context manager, which would let you write:
with BusyTracker.working:
# ... do things ...
So, virtually every function in my client code, including every component’s function, would begin with
with BusyTracker.working:
?
Maybe it’s not quite that bad. Just every function that could possibly be called while the LogOut button is visible…
You could also do it with a @decorator, I suppose. But ultimately, nothing in this system has any kind of global sense of when “something is happening” and when it’s not, so you’re going to have to tell it!
1 Like
Thank you, @meredydd. That really clarifies the challenge.
I’m starting to think about moving this button to its own form, or dropping it altogether.
1 Like