Allowing simultaneous document updates without replication conflicts
This was
one of the last just-plain-cool ideas Bill cooked up for us. Here's the situation: You have a form which lists out responsibilities for any number of different people. A Training Plan, for instance, where you have the names of all the people who need to be trained and, along with them, the names of the individuals assigned to train each one:
| Employee | Trainer |
|---|---|
| Sam Johnson | Nita Smeans |
| Alice Wan | George Wilson |
| Dave Smith | Doug Adams |
| Jack Jacobson | Nita Smeans |
| Wally Wilson | Roger Winters |
Something like that. As each person's training is completed, the trainer should be able to open this document and indicate completion. As a part of that, the form should be updated with the current date and time so everyone can know exactly who was trained and when.
The problem is you have many different trainers who may be trying to update the Training Plan at the same time. If you open it and I open it and we both make changes and save the document, guess what? We'll get replication conflicts.
Now, if we're both working from the Notes client, there are ways to guard against this. Given the same server, it will at least warn you if you try to save your document after I've saved mine. Also, it's pretty straightforward to build a means of preventing two people from editing the same document at the same time if you're using the client.
But what about from the web? In a stateless environment like the web, where the server really has no idea whether you're still looking at that page it sent you a while ago, how can you keep replication conflicts from happening and yet retain the user experience.
This was the challenge we faced.
Like so many things in life, the solution was simple once we finally hit on it. Here's what we did:
At first we thought we had to find a way to know when one person was editing a document so we could prevent others from editing it at the same time. I'll spare you the details but the short version of the story is: Don't waste your time. You can't tell.
Then we came at it from the other way: How can we let lots of different people make editing changes to the same document, at the same time, from the web, without creating replication conflicts? You can chew on it for a while but the only answer (that we could come up with, anyway) was to not allow any editing of the document directly but, instead, to do all the updates with a WebQuerySave agent.
WebQuerySave agents are single-threaded. That means only one runs at a time. So, if you and I and three other people all call the same WebQuerySave agent to run on the same document at the same time, well, it's going to do them sequentially. It will do one, then the next, then the next, and so on, until it finishes, but each will run separately.
So what we needed to do was get the WebQuerySave agent to run for us on the right bits of data. But WebQuerySave agents only run when you're saving a document and we specifically don't want to save the document (and risk creating replication conflicts). So, how to trigger it?
One way would just be to call an agent via a URL, but we decided to make a separate form which acted as a dialog box to verify your intent to continue. Pressing the OK button actually submitted that form, to which we had passed enough parameters to be able to know exactly which entry needed updating. At the end of the WebQuerySave agent it either deleted the dialog form (if the update was successful) or saved it in the database for later processing (if it failed for some reason).
Making the user experience less unsatisfying
The problem with this approach is everything was being done in the background. You'd press a button, verify your intent to continue and the WebQuerySave agent would go do the update to the underlying document...but you couldn't see the change in the browser without refreshing it.
As user feedback goes, that's pretty bad. When I've pushed the button to do the update, I want to be able to see it on the screen to know things worked properly. But, if the change is actually made on the screen, doesn't that mean I'm changing the document (and, thus, risking replication conflicts)?
Not necessarily.
On the form, each of the Trained-On dates was contained in a span, something like this:
<span id="trainDate01"></span>
On a line where training had been completed, of course, the value would show up inside the span. That's easy enough to do: put a field or some computed text in there and it will compute when the document is loaded to the browser. But what about the new ones, the lines where I've just pushed the "Training completed" button and expect to see something?
It turns out, that's simple, too. From the dialog form, when you press "OK," just before the submit we update the text in the <span> for whichever line item is being updated:
opener.document.getElementById("trainDate01").innerHTML = updateDateTime;
Really, that's all there is to it. Do a quick computation to get a value for updateDateTime (using JavaScript or even @Now in a computed text area in your code) and that's all you have to do. It's not permanent, but it feels permanent to the user. Refresh the browser and you'll lose it BUT, by that time the WebQuerySave agent will have updated the document so the same value will show up in the same place when the document is reloaded.
Best of all, with half a dozen of us hitting the same form over and over again at the same time, we can't make it cause a replication conflict. A very satisfying solution, if I may say so.
1. Mike Kinder07/05/2010 12:30:41 PM
Homepage: http://www.acadiasolutions.com
Hey Scott,
I read this with great interest as I have been in a position where this was necessary before. However, we solved it a bit differently.
Mind you, I was using a tool I wrote in the 4.6x days that managed record locking for applications. So we wanted to stop users from editing a document that was being edited - on the web. With a simple bit of @Formula and the tool I wrote we were able to accomplish this quite well.
Essentially what happed was, when a user tried to switch a document to edit mode on the web (whether directly by the URL or using a provided button) code ran that checked to see if the document was locked. If it was, we layered a div over the entire screen that told the user it was locked and could not be edited. Then with an auto refresh meta tag we sent them back to a read only version of the document 5-10 seconds later.
With the div overlaying the whole document they could not change any values nor save the changes, thus no harm in letting it open in edit mode. Also, the message told them who had the record checked out/locked and when they locked it. So if it had been some time they could contact that user and see if they could "unlock" it by saving and getting out of the document.
So we, in one solution, came up with effective record locking for the web and a way to control rep/save conflicts.
But this solution is a good one too, just wanted to mention that there was a way to, sort of anyway, "get state" of a domino document on the web.
Mike Kinder
2. Scott Good07/05/2010 02:11:16 PM
Homepage: http://www.scottgood.com
Great idea!

























