commandkit/mutex
A mutex (mutual exclusion) ensures that only one operation can access a shared resource at a time. This prevents race conditions and data corruption when multiple operations attempt to modify the same resource simultaneously.
Basic usage
The easiest way to use a mutex is with the withMutex function, which
automatically handles locking and unlocking:
import { withMutex } from 'commandkit/mutex';
// This ensures only one operation can update the shared resource at a time
const result = await withMutex('shared-resource', async () => {
  // This code runs with exclusive access
  return await updateSharedResource();
});
Custom configuration
You can create a custom mutex with different timeout settings:
import { createMutex } from 'commandkit/mutex';
const mutex = createMutex({
  timeout: 60000, // 60 second timeout
});
const result = await mutex.withLock('resource', async () => {
  return await criticalOperation();
});
Advanced usage
Manual lock management
Sometimes you need more control over when locks are acquired and released:
import { acquireLock, releaseLock, isLocked } from 'commandkit/mutex';
// Acquire lock manually
const acquired = await acquireLock('resource', 30000);
if (acquired) {
  try {
    // Perform critical operation
    await criticalOperation();
  } finally {
    // Always release the lock, even if an error occurs
    await releaseLock('resource');
  }
}
// Check if resource is currently locked
const locked = await isLocked('resource');
console.log(`Resource is ${locked ? 'locked' : 'available'}`);
Cancelling operations
You can cancel a mutex operation using an AbortSignal:
import { withMutex } from 'commandkit/mutex';
// Create a timeout that cancels after 5 seconds
const signal = AbortSignal.timeout(5000);
try {
  const result = await withMutex(
    'resource',
    async () => {
      return await longRunningOperation();
    },
    30000,
    signal,
  );
} catch (error) {
  if (error.message.includes('aborted')) {
    console.log('Lock acquisition was cancelled');
  }
}
Using external storage
Mutexes store lock information in memory by default. For multi-server deployments, use external storage like Redis:
import { Mutex, MutexStorage } from 'commandkit/mutex';
import { RedisMutexStorage } from '@commandkit/redis';
import { Redis } from 'ioredis';
// Create Redis client
const redis = new Redis();
// Use Redis-based mutex storage
const mutex = new Mutex({
  timeout: 30000,
  storage: new RedisMutexStorage(redis),
});
You can also use the convenience function:
import { createMutex } from 'commandkit/mutex';
import { RedisMutexStorage } from '@commandkit/redis';
const mutex = createMutex({
  timeout: 60000,
  storage: new RedisMutexStorage(redis),
});
Default settings
- Timeout: 30 seconds (30000ms)
- Storage: In-memory (works for single-server applications)