Need to mimic threading across controllers

Hi,

I’m hoping to make a parent and several of its dependent children
available for updates by multiple users. I want to figure out how to
implement and test the following:

  1. A user ‘checks out’ a parent resource: when seeking to update,
    other users are informed that the resource and its dependent children
    are currently unavailable for updating.

  2. A user ‘checks out’ a child resource: when seeking to update, other
    users are informed that the child is unavailable for updating, though
    the parent may be available.

I think a reason I’m stumped here is that I have little deployment
experience. Yet, even so, how would I test the behaviors above,
locally?

Thanks for any comments,

Lille

On Mar 29, 4:15pm, Lille [email protected] wrote:

  1. A user ‘checks out’ a child resource: when seeking to update, other
    users are informed that the child is unavailable for updating, though
    the parent may be available.

I think a reason I’m stumped here is that I have little deployment
experience. Yet, even so, how would I test the behaviors above,
locally?

Presumably you’ve got a flag of some sort that you set to indicate
that a record in use ? (or perhaps better than a flag, one or both of
locked_since and locked_by fields telling other users who has the
record locked). I don’t see any particular difficulties with testing
this

Fred

On Mar 29, 2011, at 11:15 AM, Lille wrote:

  1. A user ‘checks out’ a child resource: when seeking to update, other
    users are informed that the child is unavailable for updating, though
    the parent may be available.

In both of these cases, the only time that the user would “know” that
the element was locked is when they request it initially, or after a
failure to save due to a lock. Have a read of optimistic locking in
the Rails Guide. The only issue I can think of here is one of user
frustration. Let’s say they had just spent 20 minutes writing an
update to a record, now they can’t save it, and won’t ever be able to
save it because the starting point for their edit has moved underneath
them.

Walter

Thanks gents.

The nice thing about pessimistic locking for me could be that it would
help avoid the user problem to which Walter refers and I wouldn’t have
to add columns to all my models, as I would for optimistic locking.

@Fred - I see you’ve written pretty often on the topic of optimistic
locking. What, to your reckoning, are the minimum changes I’d need to
make to my models & forms to ensure the following:

  • user 1 fails to make any updates to the resource they have obtained
    from find
  • user 2 arrives later, finds the object, and should have the ability
    to update the resource

Thanks,

Lille

On 29 March 2011 16:15, Lille [email protected] wrote:

I think a reason I’m stumped here is that I have little deployment
experience. Yet, even so, how would I test the behaviors above,
locally?

Thanks for any comments,

The term you will want to Google for is “race condition”. As Fred and
Walter say, there’s no huge issue with trying to work around it - but
it can cause frustration if not handled correctly (like some kind of
“draft” save in the event of a conflict).

On Mar 29, 10:15pm, Lille [email protected] wrote:

Thanks gents.

The nice thing about pessimistic locking for me could be that it would
help avoid the user problem to which Walter refers and I wouldn’t have
to add columns to all my models, as I would for optimistic locking.

I think you are misusing terminology slightly - pessimistic locking
usually refers to database level locks (ie select … for update)
which is definitely not appropriate for this sort of scenario.

@Fred - I see you’ve written pretty often on the topic of optimistic
locking. What, to your reckoning, are the minimum changes I’d need to
make to my models & forms to ensure the following:

  • user 1 fails to make any updates to the resource they have obtained
    from find
  • user 2 arrives later, finds the object, and should have the ability
    to update the resource

Personally, unless you think you will be able to merge potentially
conflicting changes (as you would with git) the easiest think is to
mark records as locked by a user. You could build in lock expiry - if
it has been locked for over a certain duration, unlock the record
automatically

Fred

On 03/30/2011 02:26 AM, Xavier N. wrote:

Perhaps you know it, but in web programming “the last edit wins” is a
meaningful rule that allows you to get rid of these controls. If two
people edit the same form, the last received data is the one that
prevails, it doesn’t matter who requested the form first.

That’s a horrible rule and a great way to lose data. The correct rule
is the first edit wins. The last one fails and must refresh his view
and try again. This is easily accomplished by using version numbers and
failing any update where the version has changed since the initial view.


Ramon L.

Just in case, do you really need that level of locking?

Perhaps you know it, but in web programming “the last edit wins” is a
meaningful rule that allows you to get rid of these controls. If two
people edit the same form, the last received data is the one that
prevails, it doesn’t matter who requested the form first. In
particular it does not matter whether that happened in parallel or
sequentially but just immediately. The data of the first guy will be
overwritten anyway, so in practice often it does not matter.

If it does matter in your use case please just disregard this mail.

On Wed, Mar 30, 2011 at 5:59 PM, Ramon L. [email protected]
wrote:

update where the version has changed since the initial view.
Nah, I don’t think that’s right. Versioning may make sense in some
scenario
(as my comment implicitly acknowledged), but calling the rule above
“horrible” is denying the fact that it makes perfect sense in a lot of
use cases. Indeed it is the most common way to implement concurrency
handling: doing nothing because last wins is normally fine.

If user U says the state of a model is S, and user W says a
millisecond later that it is T, and the edition made by W does not
depend on the exact previous state of the model, then why you should
not believe W? He said it is T, so let it be T.

From the point of view of user U, he doesn’t know whether the requests
were interleaved or sequential, and he does not care normally. All he
knows is that after he took a bit of coffee someone else edited the
same record and now it looks different.

If the edition does depend on the previous state, then you need to put
those extra controls.

On Wed, Mar 30, 2011 at 8:41 PM, Ramon L. [email protected]
wrote:

Because you don’t know it was a millisecond later, it could have been 10
minutes later because user W sat there looking at the screen forever. User U
may have changed many fields on the model while user W just updated one and
you’ve now lost all of the data user U entered effectively rolling back the
record.

I don’t see any data loss necessarily, that depends on your
application. If W says all those fields are fine as they are, I trust
W. I trust the last one. How do you know W is wrong a priori?

The order in which the application sent the forms may be irrelevant
(again, I am using “may”). If W says the state is T, let it be T. He
was in particular saying that it is not S (for S != T if you allow me
the detail :).

It is your application who defines what’s a reasonable behavior.

On 03/30/2011 11:49 AM, Xavier N. wrote:

I don’t see any data loss necessarily, that depends on your
application.

That’s a given.

If W says all those fields are fine as they are, I trust
W. I trust the last one. How do you know W is wrong a priori?

You can’t trust W, he never saw the changes the other guy made because
he was editing an old copy. W update should fail because the record was
changed since he last viewed it and he should be shown the current data
and told to attempt his change again on the current data. If you’re
really fancy, you attempt to merge for him and ask for approval.

The order in which the application sent the forms may be irrelevant
(again, I am using “may”). If W says the state is T, let it be T. He
was in particular saying that it is not S (for S != T if you allow me
the detail :).

State is rarely a single field, T may have 20 fields where U updated 15
of them and W updated just 1 and you’re saying it’s the perfect default
behavior to lose all of U’s hard work because W made one change to an
unrelated field. That’s just crazy as a default unless you’ve
determined up front that data loss doesn’t matter. You will lose
data
.

It is your application who defines what’s a reasonable behavior.

Again, that’s a given.


Ramon L.

On 03/30/2011 11:20 AM, Xavier N. wrote:

Nah, I don’t think that’s right. Versioning may make sense in some scenario
(as my comment implicitly acknowledged), but calling the rule above
“horrible” is denying the fact that it makes perfect sense in a lot of
use cases.

I called your saying web apps are special and make last in the general
rule horrible.

Web apps aren’t special, whether first or last edit wins is decided on
whether it’s acceptable to lose data or not in a given situation
regardless of it being a web app or any other kind of app.

Indeed it is the most common way to implement concurrency
handling: doing nothing because last wins is normally fine.

That’s not implementing concurrency handling, it’s ignoring it.

If user U says the state of a model is S, and user W says a
millisecond later that it is T, and the edition made by W does not
depend on the exact previous state of the model, then why you should
not believe W? He said it is T, so let it be T.

Because you don’t know it was a millisecond later, it could have been 10
minutes later because user W sat there looking at the screen forever.
User U may have changed many fields on the model while user W just
updated one and you’ve now lost all of the data user U entered
effectively rolling back the record.

If that’s acceptable, fine, last edit wins, however, for many if not
most business type objects, it’s not OK.

From the point of view of user U, he doesn’t know whether the requests
were interleaved or sequential, and he does not care normally. All he
knows is that after he took a bit of coffee someone else edited the
same record and now it looks different.

Not just different, all of his work was lost because user W updated one
unrelated field. User U is now very pissed.


Ramon L.