Is it possible to avoid session timeouts?

I have an app that has to remain open all day. It is not authenticated. Non-technical users need to be able to go over to it, scan a badge & receive relevant information.

It works until it doesn’t. At some point, a user will scan their badge & an error message appears in the corner. Anyone with knowledge of websites can click on the bubble, see the error and refresh the site. However, this app is not built for anyone with knowledge of websites.

Is it possible to avoid session timeouts or to extend sessions to last days or weeks? I literally get called to remote in & hit F5.

Put a timer on the main form that calls a server function like this every 5 minutes :

@anvil.server.callable
def ping():
  return "pong"

I find that this keeps the comms open and hence the session open.

2 Likes

Thanks, that’s straightforward & easy to implement.

1 Like

Also another option to make it user friendly that I’ve used in the past - Custom Error Handling

https://anvil.works/docs/client/python/error-reporting

You could implement this in addition to the suggestion from @david.wylie

from anvil import set_default_error_handling
from anvil.js import window

def error_handler(err):
  if isinstance(err, anvil.server.SessionExpiredError):
    alert(
        'Your session has timed out. Please refresh the page to continue', 
        title='Session Expired' , 
        buttons=[('Refresh Now', None)],
        dismissible=False
    )
    try:
      anvil.server.reset_session()
    except:
      window.location.reload()
  else:
    alert(err.args[0], title="Error")
    # or raise err

set_default_error_handling(error_handler)

Hi Stu @stucork ,

would it also be possible to reset the session stealthily (without the user noticing) when a timeout is detected like so?

def error_handler(err):
  if type(err) == anvil.server.SessionExpiredError:
    try:
      anvil.server.reset_session()
    except:
      alert('Your session has timed out. Please refresh the page to continue', 
          title='Session Expired' , 
          buttons=[('Refresh Now', None)],
          dismissible=False)
      anvil.js.call_js('refreshSession')
  else:
    alert(err.args[0], title="Error")  

set_default_error_handling(error_handler)

Also does the implementation of the offline apps feature add anything to this issue? I would assume offline apps will have the problem of expired sessions quite frequently.

The above post doesn’t work - I thought it did when I posted it a couple of years ago.
But the SessionExpiredError doesn’t get passed to the custom default_error_handler.

There are some docs about it you can find below, which discuss how to recover from an expired session.

1 Like

That wouldn’t be an issue in my case as I am using a timer which pings the server every once in a while. That’s how I notice the expired session. My code:

  def keep_alive_timer_tick(self, **event_args):
    """This method is called Every [interval] seconds. Does not trigger if [interval] is 0."""
    try:
      anvil.server.call_s('ping')
    except:      
      try:
        print u"😴 Timeout detected. Trying to reset session!"
        anvil.server.reset_session()
        anvil.server.call_s('ping')
        print u"😎 Back online!"
      except:
        print u"😫 Reset didn't work. Reload necessary."
        if confirm("Timeout detected. Reload page now?"):
          anvil.js.call_js('refreshSession')

But actually I don’t think this is a workable solution if I have to relogin the user and (more importantly) reload all objects returned from the server after a reset.

If you call the server with an interval smaller than 30 minutes, then the session will never time out.

Perhaps the problem is different.

Perhaps there is a connection problem that causes your ping call to fail?

Have you tried adding a few prints (with a timestamp) and see what is actually executed and when?

1 Like

Thanks, Stefano, but that works fine already. My problem is with cases where somebody turns their computer into hibernate mode over night or during lunch. I’d like to avoid having to reload the app completely in this case.

1 Like

Hi there! Thanks, the ‘ping’ solution seems like a perfect solution for us too!

However I’m new to coding, and am wondering - how do you timer on the main form that calls that server function every few minutes? What code would do this, and how can it be called continuously?

Thanks so much!
Laura

Just use timer component, a quick search in the forum will show more details.

1 Like

Ah I see. Got it working, thank you!

No problem at all, please feel free to ask any further questions.

Hi
I know this is an old topic, but according to my experience, timer tick doesn’t fire if the form is not “active”

Instead, I used an infinite loop with “while True:…dosomething()…time.sleep(n)” in the startup form which keeps the client code running, even if you open another form.

I’m surprised nobody has mentioned this (or I missed it), maybe Anvil had some changes on this behaviour.

What do you mean by active?
I have apps with the timer on a tab that is not “active”, and they never timeout.

You are probably using a main form that is always open and only changing the contents in panels or tabs.
In my case, my “startup form” opens at startup and redirects the user to other forms (using “open_form”) according to their roles etc. And the timer on the startup form doesn’t fire anymore, after the second form opens.

On the other hand, I don’t see this as a bug but expected behavior, for the sake of performance and avoiding unnecessary load on the server probably.

This behavior has nothing to do with performance or server load.

This is expected because a timer is a form control just like a button or a textbox. And it does its job when its parent form is visible just like a button or a textbox.

Can you imagine the mess in an app if all the timers of all the forms were ticking, regardless of which form is currently visible?

Being able to manage multiple timers on each form gives you lots of flexibility.

1 Like