-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bf0e6b8
commit 2ddf597
Showing
5 changed files
with
71 additions
and
18 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,64 @@ | ||
import type { TaskResult } from "./types.ts"; | ||
|
||
/** | ||
* Lock that handles sequentially running asynchrounous tasks using a queue based startegy. | ||
*/ | ||
export class AsyncLock { | ||
private queue: PromiseWithResolvers<void>[]; | ||
private queue: PromiseWithResolvers<boolean>[]; | ||
|
||
constructor() { | ||
this.queue = []; | ||
} | ||
|
||
async run<T>(fn: () => Promise<T>): Promise<T> { | ||
await this.lock(); | ||
const result = await fn(); | ||
this.release(); | ||
return result; | ||
/** | ||
* Run a task asynchronously using the lock. | ||
* Places the task in the task queue and runs it as soon as any prior tasks have completed. | ||
* | ||
* @param fn - Task callback function. | ||
* @returns A promise resolving to the awaited return of the given callback function. | ||
*/ | ||
async run<const T>(fn: () => T): Promise<TaskResult<Awaited<T>>> { | ||
try { | ||
const acquiredLock = await this.acquireLock(); | ||
if (!acquiredLock) { | ||
return { | ||
status: "cancelled", | ||
}; | ||
} | ||
|
||
const value = await fn(); | ||
this.releaseLock(); | ||
return { | ||
status: "fulfilled", | ||
value: value, | ||
}; | ||
} catch (err) { | ||
this.releaseLock(); | ||
return { | ||
status: "rejected", | ||
error: err, | ||
}; | ||
} | ||
} | ||
|
||
async close(): Promise<void> { | ||
for (const lock of this.queue) { | ||
lock.resolve(); | ||
await lock.promise; | ||
/** Cancel and remove any queued tasks. */ | ||
cancel(): void { | ||
let lock = this.queue.shift(); | ||
while (lock) { | ||
lock.resolve(false); | ||
lock = this.queue.shift(); | ||
} | ||
} | ||
|
||
private async lock(): Promise<void> { | ||
private async acquireLock(): Promise<boolean> { | ||
const prev = this.queue.at(-1); | ||
const next = Promise.withResolvers<void>(); | ||
const next = Promise.withResolvers<boolean>(); | ||
this.queue.push(next); | ||
await prev?.promise; | ||
return await prev?.promise ?? true; | ||
} | ||
|
||
private release(): void { | ||
private releaseLock(): void { | ||
const lock = this.queue.shift(); | ||
lock?.resolve(); | ||
lock?.resolve(true); | ||
} | ||
} |
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
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
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