4

I want to "lock" a block of code optimistically. psuedo code is as follows:

revision = GET('lock_key') # default as 0
{
<<block of code>>
}
new_revision = INCR('lock_key')
if new_revision != revision + 1:
    raise Exception # now retry or whatever

This looks fine to me since both INCR and GET are atomic. Do you see any problem with this approach?

lazy functor
  • 2,118
  • 2
  • 15
  • 16

1 Answers1

5

There are a few problems with this approach. Firstly, it won't scale well above 2 workers since the faster ones will starve the slower. The flow also lacks atomicity, which may or may not be an issue depending the logic you're running, but race conditions are nasty. Lastly, there's a little of the observer effect in play here since you're always INCRing key_lock.

A better approach would be to use Redis' MULTI, EXEC and WATCH. Redis' transactions topic discusses this pretty neatly and provides the following example based on your psuedo code:

WATCH('lock_key')
revision = GET('lock_key') # default as 0
{
    <<block of code>>
}

MULTI()
new_revision = INCR('lock_key')
if EXEC() is None:
  raise Exception # now retry or whatever
Itamar Haber
  • 47,336
  • 7
  • 91
  • 117