My Node.js application accepts connections from the outside. Each connection handler reads a SET on Redis, eventually modifies the set itself, then moves on. The problem is that in the meanwhile another async connection can try to read the same SET and try to update it or decide its next step based on what it reads.
I know that Redis does its best to be atomic, but this is not quite sufficient for my use case. Think about this: the set is read to understand if it’s FULL (there is a business rule for that). If it’s FULL, then something happens. The problem is that if there is one only slot left, two semi-concurrent connections could think each one is the last one. And I get an overflow.
I there a way to keep a connection “waiting” for the very short time the other eventually needs to update the set state?
I think this is a corner case, very very unluckely… but you know 🙂
Using another key as the “lock” is an option, or does it stink?
You may be looking for
WATCHwithMULTI/EXEC. Here’s the pattern that both threads follow:The way this works is that all of the commands between
MULTIandEXECare queued up but not actually executed untilEXECis called. WhenEXECis called, before actually executing the queued instructions it checks to see ifsentinel_keyhas changed at all since theWATCHwas set; if it has, it returns(nil)and the queued commands are discarded. Otherwise the commands are executed atomically as a block, and it returns the number of commands executed (1 in this case), letting you know you won the race anddo_something()can be called.It’s conceptually similar to the
fork()/exec()Unix system calls – the return value from fork() tells you which process you are (parent or child). In this case it tells you whether you won the race or not.