newrelic-forks/redis-semaphore — pull request #2 by djspinmonkey (2014-12-12 22:27:25+00:00)
Title: Fix mutex logic.

This fixes a few problems with the existing logic around concurrency:

* The existing expiration logic didn't work as written, since a `getset` clears the expiration.
* The expiration logic *also* didn't work because a process could crash or be killed at any point, so it was possible to lock the mutex and then be killed before setting the expiration, thus permanently locking the mutex. This is solved by storing the locked_at timestamp in the key (instead of `API_VERSION` as currently written, which doesn't seem to have any meaning here). The handling for that is still a bit tricky: see http://redis.io/commands/setnx for a description of the logic.
* There was a potentially serious race condition where, if the `yield` (or any other part of the code) took a long time, the lock could have expired and the mutex been claimed by another process when this process comes back to delete the lock. Unfortunately, it is not possible to completely eliminate this race condition given the available redis commands, but the window has been drastically reduced.

I also changed `yield token` to just `yield`, since the "token" had no external meaning and was never used (the corresponding variable is now called `acquired`, since the actual content is a boolean indicating whether the initial attempt to acquire the mutex was successful).