Only allow a page to be open in one session at a time

I have a need to restrict a page such that only one session can have it open at a time. Has anyone done this? Looking for best practice here.

Thanks,

Frank

There's no built-in way to manage this, but I bet you could manage a check-out system which leverages a memory tag to act as the keeper of the Page.

There are two hard parts:

  1. You can't prevent someone from manually entering the URL of the Page. So you'll need to have an Embedded View act as the true Gatekeeper. Any mechanism your project would use to navigate to the page in question would need to try to obtain a "lock" for the Page by accessing the memory tag; incredibly difficult if using a Menu component as you'd need to hook into the onItemClicked Event.
  2. Tracking when someone is no longer using the page. If they navigate away within Perspective, the onShutdown Event of the VIEW can be used (or a Button which releases their hold), but this only works as long as they are doing navigation within Perspective and they never close the tab or their browser before navigating away from the page. I think a "heartbeat" timed event from the Gateway which uses the Gatekeeper tag would work for this.

The approach might change a bit depending on the rule you want enforced: should a new request always take control of the page, or should someone using the page prevent anyone else from accessing it?

You could also setup a project-wide semaphore approach through the Project Scripting Library, but I don't feel comfortable walking you through that setup.

Why can only one person view the page at a time?

3 Likes

Extending Cody's suggesting, consider a "check-out" token in a memory tag corresponding to the session ID, along with a timestamp, the user ID, and maybe an IP address (all in a one-row dataset to make it atomic, perhaps). Allow anyone to access the page/view in a readonly/disable form. Provide a status label that shows the current holder of the token if any, and how long until it expires (some fixed duration from the checkout timestamp). Provide a checkout button that is enabled when no-one has the token. Enable the entire view when the current session matches the un-expired token. (Including the checkout button, so the current holder can extend if they need more time.)

I can't answer for him, but I recently had to implement something similar.
It was a scheduling page, where the configuration of the schedule depends what already exists. So we couldn't allow 2 people to be editing it at the same time.
If someone opens this page while it's already being edited, it opens in a read-only mode until the other user leaves or validates his modifications, at which point the next user in queue gets the token and can start editing.

It was done in pretty much the way you described, with a memory tag holding the session-id of the user who currently has the "talking stick", and a heartbeat making sure the user didn't just went out for coffee. There's still a delay because it has to match the inactivity timer, but there's also a button on an admin page that allows to take the token away from someone, just in case.

Note that I also considered using a session shutdown session event to release the token, but I was afraid it would miss things. Do you think it could be used reliably ?

No a Session Shutdown would mean the user has completely closed their session out. Your users might need to do things after using the schedule. Also, when a user closes their open tabs in the browser, this is akin to a network loss for the session. The Gateway will wait up to 60 seconds (default) for the session to re-connect, so you'd have a bunch of idle time.

Yes, but it would only be to handle the case where they closed the tab/browser.
The navigation to other pages is already handled.

I was thinking a session shutdown could replace the heartbeat that's used to check if the session is still alive.

How did you do this? Did you check that it catches browser close/tab close actions? If it does, how did you do this?

I'm just checking that the session is still alive at regular intervals.
Frankly I didn't put too much thought into this, since it wasn't a requirement from the customer, I just thought I'd add a quick fix to unlock the page that was locked by a session that no longer exists.

edit:
To be a bit more accurate, it looks something like

if page_locked and session_id not in active_sessions:
    unlock_page()