Created
March 24, 2023 21:04
-
-
Save danneu/ce4b6d99e170435fa8cdc61c17233ad1 to your computer and use it in GitHub Desktop.
A queue impl where `queue.take()` returns a promise that resolves into a lock when a lock is available.
This file contains 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
// USAGE | |
const queue = new Queue(50) | |
const middleware = () => async (ctx, next: () => Promise<void>) => { | |
const lock = await queue.take() | |
await next().finally(() => { | |
queue.release(lock) | |
}) | |
} | |
// IMPL | |
class MyLock {} | |
class Ticket { | |
resolve: (_: MyLock) => void | |
constructor(resolve: (_: MyLock) => void) { | |
this.resolve = resolve | |
} | |
} | |
export default class Queue { | |
inflightCapacity: number | |
locks: Set<MyLock> | |
pending: Array<Ticket> | |
pendingCapacity: number | |
constructor(inflightCapacity: number) { | |
this.inflightCapacity = inflightCapacity | |
this.locks = new Set() | |
this.pending = [] | |
this.pendingCapacity = 1000 | |
} | |
// When you take(), you get a promise that resolves into a lock once a lock | |
// is available. | |
async take(): Promise<MyLock> { | |
if (this.locks.size < this.inflightCapacity) { | |
// There are locks available | |
const lock = new MyLock() | |
this.locks.add(lock) | |
return lock | |
} else if (this.pending.length >= this.pendingCapacity) { | |
// Drop request | |
throw new Error('OVER_CAPACITY') | |
} else { | |
// Pend until a lock is available | |
const promise = new Promise((resolve: (_: MyLock) => void) => { | |
const ticket = new Ticket(resolve) | |
this.pending.push(ticket) | |
}) | |
return promise | |
} | |
} | |
release(lock: MyLock) { | |
this.locks.delete(lock) | |
for (let i = 0; i < this.inflightCapacity - this.locks.size; i++) { | |
// const ticket = this.pending.pop() | |
const ticket = this.pending.shift() | |
if (!ticket) { | |
return | |
} | |
const lock = new MyLock() | |
this.locks.add(lock) | |
ticket.resolve(lock) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment