Skip to content

Instantly share code, notes, and snippets.

@slavikme
Last active September 19, 2024 07:15
Show Gist options
  • Save slavikme/5486eddcde3adef75b1923bed783141a to your computer and use it in GitHub Desktop.
Save slavikme/5486eddcde3adef75b1923bed783141a to your computer and use it in GitHub Desktop.
Parallel Job Runner
/**
* Creates a function that performs any promisable task in parallel.
* @param {number} [concurrency] - The maximum number of concurrent jobs that are able to run simultaneously.
* @return {Promise}
*/
const createJobRunner = (concurrency = 3) => {
const EMPTY_SLOT = false;
const BUSY_SLOT = true;
const workersQueue = [];
const workingSlots = new Array(concurrency).fill(EMPTY_SLOT);
const next = (availableSlot = workingSlots.indexOf(EMPTY_SLOT)) => {
if (workersQueue.length === 0 || availableSlot < 0) return;
workingSlots[availableSlot] = BUSY_SLOT;
const worker = workersQueue.shift();
worker(() => {
workingSlots[availableSlot] = EMPTY_SLOT;
next(availableSlot)
});
}
return (worker) => new Promise( (resolve, reject) => {
workersQueue.push((onFinish) => {
const job = worker();
if (job instanceof Promise) {
job.then(resolve).catch(reject).finally(onFinish);
} else {
try {
resolve(job);
} catch (e) {
reject(e);
} finally {
onFinish();
}
}
});
next();
});
}
const doWork = createJobRunner(5);
for (let i=0; i<10; i++) {
doWork(() => new Promise((resolve) => {
console.log(`Job ${i} started`);
setTimeout(() => {
console.log(`Job ${i} done`);
resolve();
}, Math.random() * 1000)
}));
}
//// Possible output:
// Job 0 started
// Job 1 started
// Job 2 started
// Job 3 started
// Job 4 started
// Job 1 done
// Job 5 started
// Job 5 done
// Job 6 started
// Job 2 done
// Job 7 started
// Job 7 done
// Job 8 started
// Job 4 done
// Job 9 started
// Job 3 done
// Job 0 done
// Job 8 done
// Job 6 done
// Job 9 done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment