Concurrency – What to Do When Optimistic Locking Doesn’t Work

concurrencyhttplanguage-agnosticrest

I have this following scenario:

  1. A user makes a GET request to /projects/1 and receives an ETag.
  2. The user makes a PUT request to /projects/1 with the ETag from step #1.
  3. The user makes another PUT request to /projects/1 with the ETag from step #1.

Normally, the second PUT request would receive a 412 response, since the ETag is now stale – the first PUT request modified the resource, so the ETag doesn't match anymore.

But what if the two PUT requests are sent at the same time (or exactly one after the other)? The first PUT request does not have time to process and update the resource before PUT #2 arrives, which causes PUT #2 to overwrite PUT #1. The whole point of optimistic locking is for that not to happen…

Best Answer

The ETag mechanism specifies only the communication protocol for optimistic locking. It's the responsibility of the application service to implement the mechanism to detect concurrent updates to enforce the optimistic lock.

In a typical application that uses a database, you'd usually do this by opening a transaction when processing a PUT request. You'd normally read the existing state of the database inside that transaction (to gain a read lock), check your Etag validity, and overwrite the data (in a way that'll cause a write conflict when there's any incompatible concurrent transaction), then commit. If you setup the transaction correctly, then one of the commits should fail because they'll both be trying to update the same data concurrently. You'll then be able to use this transaction failure to either return 412 or retry the request, if it makes sense for the application.

Related Topic