Dmitry Shpika // scriptin
type Links = GitHub | LinkedIn | YouTube | StackExchange | NPM;

RESTful HTTP: concurrency control with optimistic locking

Published on 30 Aug 2014

3 mins read

The Problem

This is known as the lost update problem:

  1. Agent A reads some data record (from your RESTful API in this case). Example: billing account of some user.
  2. Agent B reads the same record.
  3. Agent A modifies some fields in the record and saves the record. Example: $100 was added.
  4. Agent B also modifies the data in some other way and saves it without checking if something has changed between the moment the record was read and the moment it is to be saved. Example: $1 was added.

Result: $99 is gone because second update overridden the first one. The first one is lost, hence the name of the problem.

Sequence diagram: Optimistic Offline Lock in Martin Fowler’s Catalog of Patterns of Enterprise Application Architecture

The Solution

There are several ways to prevent this, and optimistic locking is the one that best fits the case of RESTful APIs:

  1. Agent A reads some data record, API returns a version of this record together with data itself. In HTTP, this is done via ETag header Example: the version is ETag: W/"1". It can be any string, usually an ordinal number or a checksum of data. W/ means “weak” validation, which is semantic equivalence instead of byte-to-byte equality.
  2. Agent B reads the same records with the same version.
  3. Agent A modifies some fields in the record and saves the record, passing If-Match: W/"1". Server accepts changes and increments the version.
  4. Agent B also modifies the data and also tries to save it with If-Match: W/"1" being passed. Server rejects those changes because the version has changed. This must be done by sending a response with 412 Precondition Failed status. If no If-Match header is provided by a client, server must respond with 428 Precondition Required status.

Advantages

Disadvantages

And that’s the only one real disadvantage I’m aware of.

Support by frameworks

If your framework (I mean ORM or other database frameworks) doesn’t support optimistic locking, I’d suggest you choose a different one if you’re going to implement RESTful API.

This is how it’s done in some Java frameworks:

Other frameworks with explicit support I know:

By explicit support of optimistic locking I mean that there is a special function/annotation/property just for that. If there isn’t, you still can do this manually by checking version in your code or adding something like WHERE VERSION = :version to your SQL.

You can do concurrency control even with no framework at all, so don’t be upset if your favorite ORM lacks explicit support.

Further reading