DEV Community

Cover image for Introducing mutex-forge: Mutex & Semaphore for async JavaScript
Javon Ayers
Javon Ayers

Posted on

Introducing mutex-forge: Mutex & Semaphore for async JavaScript

JavaScript is single-threaded, but async code still races. Two functions can await at the same time and both update shared state — caches, balances, worker message flows. Those bugs are hard to reproduce.

I built mutex-forge to bring classic mutex and semaphore patterns to async JavaScript and TypeScript.

What it does

  • Mutex — exclusive access to a critical section
  • Semaphore — limit how many jobs run at once (pools, rate limits)
  • runExclusive — acquire, run, and release automatically
  • withTimeout — fail if the lock takes too long
  • tryAcquire — non-blocking lock attempts
  • TypeScript types included

Example: prevent overlapping updates


javascript
const { Mutex } = require('mutex-forge');

const mutex = new Mutex();
let balance = 0;

async function credit(amount) {
  await mutex.runExclusive(async () => {
    const current = balance;
    await someAsyncWork();
    balance = current + amount;
  });
}

await Promise.all([credit(10), credit(20)]);
// balance === 30
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
javonayers999 profile image
Javon Ayers

This is a great addition to the async JS toolkit — race conditions from overlapping await calls are exactly the kind of bug that's easy to write and painful to debug. Love that mutex-forge includes tryAcquire and withTimeout out of the box, since those are the parts people usually end up hand-rolling themselves. Definitely adding the mutex-forge npm package to my toolbox for the next time I'm dealing with shared state across concurrent async calls.