One of the reasons why Javascript has become such a success is due to its lack of concurrency problems as a result of the awesome event loop.
However, when talking to external systems one may run into concurrency problems all over again.
For example, let's say we have some-command
that does not support concurrency and we happen to be calling in a request.
How do we ensure our Node.js backend serializes calls to some-command
?
Whenever I have a concurrency problem, the first thing I reach for is throat
. But throat
is tricky to use here. In order to use throat
we would need to gather all the requests to some-command
into a common queue, then re-map it back to the request. This is doable, but there is a simpler way.
What we really want is mutual exclusion, aka a mutex. What would be nice is if the mutex was just a simple promise.
Now if there are multiple concurrent requests, they would all attempt to resolve acquire
, but if we only let one through at a time, we have achieved our goal.
There are a few ways to implement acquire
/release
and the implementations I've found tend to be really bad. Often they are overly complicated using EventEmitter
or pointlessly implemented with class
.
Here is how I would implement acquire
/release
Note await undefined
does resolve, which is why await semaphore
is fine.
That showed the mechanics, but this code isn't reusable. Also the try
/finally
is annoying to write every single time. We can clean all this up with a factory function.
Then the usage would look like,
Can you gork race conditions? We'd like to hear from you, Battlefy is hiring.