Distributed Locking With NodeJs and Mongo
In a distributed environment with multiple instances of a service running at once, you may want to run a task (i.e. a scheduled job) and ensure that task is only run by a single instance and not by all of your instances, otherwise it might break your process. One possible solution for that is distributed locking to ensure that the process does not run multiple times in parallel.
With distributed locking, before the actual process starts, the service tries to acquire a lock, if there already is an existing lock, the process will exit, if not, a lock is acquired. An easy way to do this, is by leveraging a database that ensures that an entry cannot be written twice at the same time — this way, we can safely acquire a lock and any conflict is recognized.
I’d like to show you a simple distributed lock using NodeJS and Mongo — here’s a breakdown of the two possible scenarios:
Here’s a very simple example of acquiring a lock with NodeJs and Mongo:
When we want to run something once and ensure it does not run in parallel in a distributed environment, we can now call acquireAndExecute('lockName', () => { // code })
.
Now, there are a few considerations:
- If your code throws an exception, the lock should still be released, otherwise it stays there and will never run again, as acquiring the lock will fail
- You should automatically release your lock after some time, to ensure a very long running process or your process timing out does not block any future runs
The first consideration can easily be solved with a try-catch. For the second considerations, we can leverage a feature that MongoDB provides: Expiring indices. With an expiring index, MongoDB will automatically remove the entry. So let’s improve our distributed locking service:
Here’s a sample usage of your distributed locking service
Now you have a distributed lock with automatic expiry and safe error-handling using NodeJS and Mongo. Have you implemented distributed locking before? How do you usually solve it?