How to take an app "down" for "maintenance"?

For more complex apps, it can be useful to build an App as at least two editions: Development and Production. That way, we can render Dev unusable as often as we want (and sometimes unintentionally) without impacting actual users.

Even so, Production must still be updated, from time to time, to provide new features (and bug fixes). Where database tables are involved, some kinds of updates can’t (or shouldn’t) be done while a user is logged in, and users shouldn’t be allowed back in until the update is completed (and basic sanity checks run).

How do you guys go about bringing an App down, for such maintenance/update/testing?

I haven’t tried, but I think that creating a “closed for maintenance” form and setting it as startup form in the published version, then playing around with the main form as startup form in the development version should work.

If it looks like I’m thinking out loud, here, it’s because I am. It helps get context (and its requirements) out in the open, where others can chime in with questions and ideas.

My app uses a commonplace timer-based session-extension technique (I call it a “user heartbeat”). It allows users to remain connected during entry of complex data. So its primary issue is not “how do I prevent users from logging in”, but how do I make sure that currently-connected users disconnect, and stay disconnected, until the coast is clear.

I think I’ll have to extend the overall “heartbeat” mechanism so that it can

  1. tell when a shutdown is needed
  2. save the user’s data and log out
  3. prevent the user from logging back in.
  4. allow them to log back in once the shutdown has ended

Equally, server-side, I have to know when all users have logged out, so that the corresponding maintenance steps know when they can proceed safely.

This is somewhat complicated by the fact that a user may be logged in from several different browser tabs simultaneously, often, without even knowing it. For example, they may have started working on their data during lunch hour at work, and want to continue that work at home, having left work with their work browser minimized and forgotten, but not actually closed.

This makes it clear that we should not be talking about users, per se, but user-sessions. A list of active sessions would be needed. When this list shrinks to empty, then maintenance can proceed.

There are scores of different things that might trigger a shutdown: data backups/restores; bug fixes (server-side, client-side, or both); changes in third-party services (including those provided via Uplink); database content/structure changes; visual updates; …

Fortunately, the mechanism doesn’t have to care about causes. It need only concern itself with effects.

How about:

  1. you click on “go in maintenance mode” on your admin page
  2. on each client, the next time the timer pings the server, let’s say once every x minutes, if finds out that the maintenance is imminent and shows a “you have y minutes to save” warning
  3. after y minutes, if the user doesn’t explicitly save, the timer will save as a draft
  4. after x+y minutes you are free to set the “out for maintenance” form as startup

I like this workflow. Step 1 can trigger a database entry, so it’s visible to all open sessions. Subsequent operating states (in-maintenance, normal operation) can be in the database in the same fashion.

One catch during step 2: since there is no such thing as a “modal dialog box” in Anvil, we use pop-up (alert) boxes extensively for in-depth data-entry. (The amount of screenspace required otherwise would be very intimidating.)

Alerts do not nest. But maybe a Notification will work even when an Alert is open.

You could add an invisible label at the top of the form and make it visible when the warning is required.

It’s ugly because you would need to add this label on every form, but on the other hand, now you have a notification area that you can use for other types of notifications.

Thanks, @stefano.menci, that’s a terrific idea!

As you say, it’d be worth doing anyway.