Last active
January 24, 2024 15:42
-
-
Save andrew--r/6e45f2b1661cabec9ea7d0d0bb972e50 to your computer and use it in GitHub Desktop.
node-core-library LockFile error
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {Async} = require('@rushstack/node-core-library'); | |
const {runWithLock} = require('./runWithLock'); | |
function simulateLockedOperation() { | |
return runWithLock(async () => { | |
await Async.sleep(250); | |
}); | |
} | |
async function run() { | |
const promises = []; | |
for (let i = 0; i < 100; i++) { | |
promises.push(upload()); | |
} | |
await Promise.all(promises); | |
} | |
run(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {LockFile} = require('@rushstack/node-core-library'); | |
let locked = false; | |
const currentProcessQueue = []; | |
/** | |
* Unfortunately, currently LockFile works only across different processes, | |
* so we need to handle current process calls manually | |
*/ | |
function acquireCurrentProcessLock() { | |
return new Promise((resolve) => { | |
const release = () => { | |
locked = false; | |
const next = currentProcessQueue.shift(); | |
if (next) { | |
next(release); | |
} | |
}; | |
if (locked) { | |
currentProcessQueue.push(() => { | |
locked = true; | |
resolve(release); | |
}); | |
} else { | |
locked = true; | |
resolve(release); | |
} | |
}); | |
} | |
/** | |
* Runs operation with interprocess lock to ensure | |
* two operations can’t run simultaneously | |
* | |
* @param {() => Promise<unknown>} operation | |
*/ | |
async function runWithLock(operation, {timeout} = {timeout: 1000 * 60 * 30}) { | |
const abortController = new AbortController(); | |
const {pid} = process; | |
const run = async () => { | |
const release = await acquireCurrentProcessLock(); | |
if (abortController.signal.aborted) { | |
release(); | |
return; | |
} | |
let interProcessLock; | |
try { | |
interProcessLock = await LockFile.acquire(__dirname, 'joom-crowdin'); | |
await operation(); | |
} finally { | |
interProcessLock?.release(); | |
release(); | |
} | |
}; | |
let timer; | |
await Promise.race([ | |
run(), | |
new Promise((_, reject) => { | |
timer = setTimeout(() => { | |
abortController.abort(); | |
reject(new Error('joom-crowdin: Lock acquiring timeout reached')); | |
}, timeout); | |
if (typeof timer !== 'number' && 'unref' in timer) { | |
timer.unref(); | |
} | |
}), | |
]); | |
clearTimeout(timer); | |
} | |
module.exports = {runWithLock}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment