有些本地脚本会被 cron、手动命令或者队列重复拉起。Node 里不想额外装依赖的话,可以用 fs.mkdir() 创建锁目录:创建成功表示拿到锁,目录已存在就直接退出。
环境:Node.js 20+,Linux/macOS/Windows,只用内置模块。保存为 lock-demo.mjs:
import { mkdir, rm, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
const lockDir = join(tmpdir(), 'node-mkdir-lock-demo.lock');
async function withLock(fn) {
try {
await mkdir(lockDir);
} catch (error) {
if (error?.code === 'EEXIST') {
console.error('another process is running');
process.exitCode = 75;
return;
}
throw error;
}
try {
await writeFile(join(lockDir, 'pid'), `${process.pid}\n`, 'utf8');
await fn();
} finally {
await rm(lockDir, { recursive: true, force: true });
}
}
await withLock(async () => {
console.log(`start pid=${process.pid}`);
await new Promise((resolve) => setTimeout(resolve, Number(process.argv[2] ?? 2000)));
console.log(`done pid=${process.pid}`);
});
验证一下第二个进程会拿不到锁:
node lock-demo.mjs 3000 &
sleep 0.2
node lock-demo.mjs 100
wait
这个办法适合单机上的小脚本。真正跑生产任务时还要想一下“进程被 kill 后锁目录残留”的清理策略,比如记录 pid 和时间戳,启动时判断是不是过期锁。