Preventing State Corruption with Atomic Mutex Locks in Node.js
How to build safe filesystem-based lock primitives to run concurrent background agents without race conditions.
The Concurrency Threat in Automated Workspaces
When building custom, autonomous software agents that write and compile files on the same repository concurrently, race conditions are inevitable. If a daily compliance audit script modifies your codebase while a deployment is running, or if two webhook requests edit the same file simultaneously, state corruption occurs.
To solve this, we engineer a filesystem-based atomic mutex lock primitive.
The Atomic Mutex Pattern
In Node.js and Bun, we can achieve true atomic file locking using native file system write options. Specifically, passing the exclusive write flag wx to fs.promises.writeFile guarantees that the write operation will fail if the file already exists.
Here is the exact TypeScript implementation of our atomic mutex lock:
import { promises as fs } from 'fs';
import * as path from 'path';
export class FileMutex {
private lockPath: string;
private holderPid: string;
constructor(lockName: string = 'agent.lock') {
this.lockPath = path.join(process.cwd(), lockName);
this.holderPid = process.pid.toString();
}
/
Locked by PID ${this.holderPid} at ${new Date().toISOString()}, { flag: 'wx' });
return true;
} catch (err: any) {
if (err.code === 'EEXIST') {
// Lock is currently held by another process
return false;
}
throw err;
}
}
/
⚠️ Reaped stale lock file (age: ${Math.round(ageMs / 60000)} minutes).);
return true;
}
return false;
} catch {
return false; // No lock file exists
}
}
}
Self-Healing and Stale Lock Recovery
To make this mutex completely self-healing, the runner first executes reapStaleLock() before trying to acquire. If the lock was created by an execution process that crashed or hung, the background loop automatically unlinks the file and logs a warning to Slack.
By wrapping our background agents and webhook handlers in this FileMutex, we guarantee that only one writer touches our files at any given second, ensuring perfect database and repository integrity.