As machines scale up in number, benefits you had when using a single-instance running your softwares are lost, among which we find operating with shared resources in a mutually exclusive way. Alright, what's that in human words?
Well, think like you need to send an email to all customers every day: given you only have one server that is pretty easy to achieve even with a simple unix cronjob that runs at midnight every day. The problem is when you have more than one machine up and running in the wild and you do need to ensure such operation is only fired once per day. Suddenly you cannot use hard-coded per-machine logic like cronjobs!
We then would need a way to lock down (hold) further attempts to do such operation once the first one has started, meanwhile guaranteeing:
- 1. Mutual exclusion: at any given moment, only one client can hold a lock.
- 2. Deadlock free: eventually it is always possible to acquire a lock, even if the client that locked a resource crashes.
- 3. Fault tolerance: as long as the majority of machines (or nodes) are up, the software (aka client) should be able to acquire and release locks.
Fortunately enough, systems like Redis can help us dealing with this. Given a Redis client, we can use the following command to store a key when it does not exist:
![](https://s3-eu-central-1.amazonaws.com/squallstar.it/images/post/1519829191940-redis1.png)
The random value is used in order to release the lock in a safe way, with a script that tells Redis: remove the key only if it exists and the value stored at the key is exactly the one I expect to be. This is accomplished by the following Lua script:
![](https://s3-eu-central-1.amazonaws.com/squallstar.it/images/post/1519829617756-redis-2.png)
The time we use as the key time to live, is called the “lock validity time”. It is both the auto release time, and the time the client has in order to perform the operation required before another client may be able to acquire the lock again, without technically violating the mutual exclusion guarantee, which is only limited to a given window of time from the moment the lock is acquired.
There's plenty of libraries out there that follows the above pattern for a multitude of programming languages. Let's take a look at a Node.js-based implementation by the redislock npm package:
![](https://s3-eu-central-1.amazonaws.com/squallstar.it/images/post/1519829882574-redis-3.png)
If we take even one more step forward, we can look at the nice cron-cluster npm library which integrates a similar concept using redis-leader and cronjobs all within the same lib:
![](https://s3-eu-central-1.amazonaws.com/squallstar.it/images/post/1519830101358-redis-5.png)