diff --git a/README.md b/README.md index 95c30b8..f4d6e71 100644 --- a/README.md +++ b/README.md @@ -535,6 +535,79 @@ tryAcquire(semaphoreOrMutex, new Error('new fancy error')) // ... }); ``` + +# Migration Guide +When migrating away from version [] to version [], make the following changes: +- The `acquire`, `runExclusive`, and `waitForUnlock` methods no longer accept weight or priority parameters directly. They are wrapped in an optional options object instead. For example, replace: + +Examples with `Semaphore`: +```typescript +semaphore.acquire() // No change needed + +semaphore.acquire(2, 5) // Old +semaphore.acquire({ weight: 2, priority: 5 }) // New + +semaphore.acquire(undefined, 5) // Old +semaphore.acquire({ priority: 5 }) // New +semaphore.acquire({ weight: 1, priority: 5 }) // Equivalent + +semaphore.acquire(2) // Old +semaphore.acquire({ weight: 5 }) // New + + +// runExclusive: same change to weight and priority as with acquire() + +// No change: +semaphore.runExclusive((value: number) => { + doSomeWork() +}); + +// Old +semaphore.runExclusive((value: number) => { + doSomeWork() +}, 2, -1) + +// New +semaphore.runExclusive((value: number) => { + doSomeWork() +}, { weight: 2, priority: -1 }) + + +// waitForUnlock: same + +semaphore.waitForUnlock(2, 3) // Old +semaphore.waitForUnlock({ weight: 2, priority: 3 }) // New +``` + +Examples with `Mutex`: +```typescript +mutex.acquire() // No change needed + +mutex.acquire(-1) // Old +mutex.acquire({ priority: -1 }) // New + +// No change: +mutex.runExclusive(() => { + doSomeWork() +}) + +// Old: +mutex.runExclusive(() => { + doSomeWork() +}, 1) + +// New: +mutex.runExclusive(() => { + doSomeWork() +}, { priority: 1 }) + + +mutex.waitForUnlock() // No change + +mutex.waitForUnlock(5) // Old +mutex.waitForUnlock({ priority: 5 }) // New +``` + # License Feel free to use this library under the conditions of the MIT license. diff --git a/src/Mutex.ts b/src/Mutex.ts index 20cffd6..daf258f 100644 --- a/src/Mutex.ts +++ b/src/Mutex.ts @@ -1,4 +1,4 @@ -import MutexInterface from './MutexInterface'; +import { MutexOptions, MutexInterface } from './MutexInterface'; import Semaphore from './Semaphore'; class Mutex implements MutexInterface { @@ -6,22 +6,22 @@ class Mutex implements MutexInterface { this._semaphore = new Semaphore(1, cancelError); } - async acquire(priority = 0): Promise { - const [, releaser] = await this._semaphore.acquire(1, priority); + async acquire(options?: MutexOptions): Promise { + const [, releaser] = await this._semaphore.acquire(options); return releaser; } - runExclusive(callback: MutexInterface.Worker, priority = 0): Promise { - return this._semaphore.runExclusive(() => callback(), 1, priority); + runExclusive(callback: MutexInterface.Worker, options?: MutexOptions): Promise { + return this._semaphore.runExclusive(() => callback(), options); } isLocked(): boolean { return this._semaphore.isLocked(); } - waitForUnlock(priority = 0): Promise { - return this._semaphore.waitForUnlock(1, priority); + waitForUnlock(options?: MutexOptions): Promise { + return this._semaphore.waitForUnlock(options); } release(): void { diff --git a/src/MutexInterface.ts b/src/MutexInterface.ts index c09f22a..5a365b5 100644 --- a/src/MutexInterface.ts +++ b/src/MutexInterface.ts @@ -1,9 +1,9 @@ -interface MutexInterface { - acquire(priority?: number): Promise; +export interface MutexInterface { + acquire(options?: MutexOptions): Promise; - runExclusive(callback: MutexInterface.Worker, priority?: number): Promise; + runExclusive(callback: MutexInterface.Worker, options?: MutexOptions): Promise; - waitForUnlock(priority?: number): Promise; + waitForUnlock(options?: MutexOptions): Promise; isLocked(): boolean; @@ -12,7 +12,11 @@ interface MutexInterface { cancel(): void; } -namespace MutexInterface { +export interface MutexOptions { + priority?: number; +} + +export namespace MutexInterface { export interface Releaser { (): void; } diff --git a/src/Semaphore.ts b/src/Semaphore.ts index b912f2d..17ba2a2 100644 --- a/src/Semaphore.ts +++ b/src/Semaphore.ts @@ -1,5 +1,5 @@ import { E_CANCELED } from './errors'; -import SemaphoreInterface from './SemaphoreInterface'; +import { SemaphoreOptions, SemaphoreInterface } from './SemaphoreInterface'; interface Priority { @@ -21,7 +21,10 @@ interface Waiter { class Semaphore implements SemaphoreInterface { constructor(private _value: number, private _cancelError: Error = E_CANCELED) {} - acquire(weight = 1, priority = 0): Promise<[number, SemaphoreInterface.Releaser]> { + acquire(options?: SemaphoreOptions): Promise<[number, SemaphoreInterface.Releaser]> { + options = options || { weight: 1, priority: 0 }; + const weight = options.weight !== undefined ? options.weight : 1; + const priority = options.priority !== undefined ? options.priority : 0; if (weight <= 0) throw new Error(`invalid weight ${weight}: must be positive`); return new Promise((resolve, reject) => { @@ -36,8 +39,8 @@ class Semaphore implements SemaphoreInterface { }); } - async runExclusive(callback: SemaphoreInterface.Worker, weight = 1, priority = 0): Promise { - const [value, release] = await this.acquire(weight, priority); + async runExclusive(callback: SemaphoreInterface.Worker, options?: SemaphoreOptions): Promise { + const [value, release] = await this.acquire(options); try { return await callback(value); @@ -46,7 +49,9 @@ class Semaphore implements SemaphoreInterface { } } - waitForUnlock(weight = 1, priority = 0): Promise { + waitForUnlock(options?: SemaphoreOptions): Promise { + const weight = options?.weight !== undefined ? options.weight : 1; + const priority = options?.priority || 0; if (weight <= 0) throw new Error(`invalid weight ${weight}: must be positive`); if (this._couldLockImmediately(weight, priority)) { diff --git a/src/SemaphoreInterface.ts b/src/SemaphoreInterface.ts index 14e40f6..7c3ac99 100644 --- a/src/SemaphoreInterface.ts +++ b/src/SemaphoreInterface.ts @@ -1,9 +1,9 @@ -interface SemaphoreInterface { - acquire(weight?: number, priority?: number): Promise<[number, SemaphoreInterface.Releaser]>; +export interface SemaphoreInterface { + acquire(options?: SemaphoreOptions): Promise<[number, SemaphoreInterface.Releaser]>; - runExclusive(callback: SemaphoreInterface.Worker, weight?: number, priority?: number): Promise; + runExclusive(callback: SemaphoreInterface.Worker, options?: SemaphoreOptions): Promise; - waitForUnlock(weight?: number, priority?: number): Promise; + waitForUnlock(options?: SemaphoreOptions): Promise; isLocked(): boolean; @@ -16,7 +16,12 @@ interface SemaphoreInterface { cancel(): void; } -namespace SemaphoreInterface { +export interface SemaphoreOptions { + weight?: number; + priority?: number; +} + +export namespace SemaphoreInterface { export interface Releaser { (): void; } diff --git a/src/withTimeout.ts b/src/withTimeout.ts index 77e232f..a81cf6d 100644 --- a/src/withTimeout.ts +++ b/src/withTimeout.ts @@ -1,22 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { E_TIMEOUT } from './errors'; -import MutexInterface from './MutexInterface'; -import SemaphoreInterface from './SemaphoreInterface'; +import { MutexInterface, MutexOptions } from './MutexInterface'; +import { SemaphoreInterface, SemaphoreOptions } from './SemaphoreInterface'; export function withTimeout(mutex: MutexInterface, timeout: number, timeoutError?: Error): MutexInterface; export function withTimeout(semaphore: SemaphoreInterface, timeout: number, timeoutError?: Error): SemaphoreInterface; export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout: number, timeoutError = E_TIMEOUT): any { return { - acquire: (weightOrPriority?: number, priority?: number): Promise => { - let weight: number | undefined; - if (isSemaphore(sync)) { - weight = weightOrPriority; - } else { - weight = undefined; - priority = weightOrPriority; - } - if (weight !== undefined && weight <= 0) { - throw new Error(`invalid weight ${weight}: must be positive`); + acquire: (options?: SemaphoreOptions | MutexOptions): Promise => { + options = options || { weight: 1, priority: 0 }; + if ('weight' in options && options.weight !== undefined && options.weight <= 0) { + throw new Error(`invalid weight ${options.weight}: must be positive`); } return new Promise(async (resolve, reject) => { @@ -28,10 +22,7 @@ export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout: }, timeout); try { - const ticket = await (isSemaphore(sync) - ? sync.acquire(weight, priority) - : sync.acquire(priority) - ); + const ticket = await sync.acquire(options); if (isTimeout) { const release = Array.isArray(ticket) ? ticket[1] : ticket; @@ -50,11 +41,11 @@ export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout: }); }, - async runExclusive(callback: (value?: number) => Promise | T, weight?: number, priority?: number): Promise { + async runExclusive(callback: (value?: number) => Promise | T, options?: MutexOptions | SemaphoreOptions): Promise { let release: () => void = () => undefined; try { - const ticket = await this.acquire(weight, priority); + const ticket = await this.acquire(options); if (Array.isArray(ticket)) { release = ticket[1]; @@ -78,24 +69,15 @@ export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout: return sync.cancel(); }, - waitForUnlock: (weightOrPriority?: number, priority?: number): Promise => { - let weight: number | undefined; - if (isSemaphore(sync)) { - weight = weightOrPriority; - } else { - weight = undefined; - priority = weightOrPriority; - } - if (weight !== undefined && weight <= 0) { - throw new Error(`invalid weight ${weight}: must be positive`); + waitForUnlock: (options?: MutexOptions | SemaphoreOptions): Promise => { + options = options || { weight: 1, priority: 0 }; + if ('weight' in options && options.weight !== undefined && options.weight <= 0) { + throw new Error(`invalid weight ${options.weight}: must be positive`); } return new Promise((resolve, reject) => { const handle = setTimeout(() => reject(timeoutError), timeout); - (isSemaphore(sync) - ? sync.waitForUnlock(weight, priority) - : sync.waitForUnlock(priority) - ).then(() => { + sync.waitForUnlock(options).then(() => { clearTimeout(handle); resolve(); }); @@ -109,7 +91,3 @@ export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout: setValue: (value: number) => (sync as SemaphoreInterface).setValue(value), }; } - -function isSemaphore(sync: SemaphoreInterface | MutexInterface): sync is SemaphoreInterface { - return (sync as SemaphoreInterface).getValue !== undefined; -} diff --git a/test/mutex.ts b/test/mutex.ts index d945209..7ccd676 100644 --- a/test/mutex.ts +++ b/test/mutex.ts @@ -41,19 +41,19 @@ export const mutexSuite = (factory: (cancelError?: Error) => MutexInterface): vo const values: number[] = []; // Scheduled immediately - mutex.acquire(0).then((release) => { + mutex.acquire({ priority: 0 }).then((release) => { values.push(0); setTimeout(release, 100) }); // Low priority task - mutex.acquire(-1).then((release) => { + mutex.acquire({ priority: -1 }).then((release) => { values.push(-1); setTimeout(release, 100) }); // High priority task; jumps the queue - mutex.acquire(1).then((release) => { + mutex.acquire({ priority: 1 }).then((release) => { values.push(1); setTimeout(release, 100) }); @@ -110,9 +110,9 @@ export const mutexSuite = (factory: (cancelError?: Error) => MutexInterface): vo test('runExclusive unblocks the highest-priority task first', async () => { const values: number[] = []; - mutex.runExclusive(() => { values.push(0); }, 0); - mutex.runExclusive(() => { values.push(-1); }, -1); - mutex.runExclusive(() => { values.push(+1); }, +1); + mutex.runExclusive(() => { values.push(0); }, { priority: 0 }); + mutex.runExclusive(() => { values.push(-1); }, { priority: -1 }); + mutex.runExclusive(() => { values.push(+1); }, { priority: +1 }); await clock.runAllAsync(); assert.deepStrictEqual(values, [0, +1, -1]); }); @@ -303,20 +303,20 @@ export const mutexSuite = (factory: (cancelError?: Error) => MutexInterface): vo }); test('waitForUnlock unblocks high-priority waiters before low-priority queued tasks', async () => { - mutex.acquire(0); // Immediately scheduled - mutex.acquire(0); // Waiting + mutex.acquire({ priority: 0 }); // Immediately scheduled + mutex.acquire({ priority: 0 }); // Waiting let flag = false; - mutex.waitForUnlock(1).then(() => { flag = true; }); + mutex.waitForUnlock({ priority: 1 }).then(() => { flag = true; }); mutex.release(); await clock.tickAsync(0); assert.strictEqual(flag, true); }); test('waitForUnlock unblocks low-priority waiters after high-priority queued tasks', async () => { - mutex.acquire(0); // Immediately scheduled - mutex.acquire(0); // Waiting + mutex.acquire({ priority: 0 }); // Immediately scheduled + mutex.acquire({ priority: 0 }); // Waiting let flag = false; - mutex.waitForUnlock(-1).then(() => { flag = true; }); + mutex.waitForUnlock({ priority: -1 }).then(() => { flag = true; }); mutex.release(); await clock.tickAsync(0); assert.strictEqual(flag, false); diff --git a/test/semaphoreSuite.ts b/test/semaphoreSuite.ts index c75a179..e098a27 100644 --- a/test/semaphoreSuite.ts +++ b/test/semaphoreSuite.ts @@ -35,11 +35,11 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('acquire with weight does block while the semaphore has reached zero until it is released again', async () => { const values: Array = []; - semaphore.acquire(2).then(([value, release]) => { + semaphore.acquire({ weight: 2 }).then(([value, release]) => { values.push(value); setTimeout(release, 100); }); - semaphore.acquire(1).then(([value]) => values.push(value)); + semaphore.acquire({ weight: 1 }).then(([value]) => values.push(value)); await clock.tickAsync(0); @@ -52,21 +52,22 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('acquire unblocks high-priority tasks first', async () => { const values: Array = []; + semaphore.setValue(1); // priority=0; runs first because nothing else is waiting - semaphore.acquire(2, 0).then(([, release]) => { + semaphore.acquire({ priority: 0 }).then(([, release]) => { values.push(0); setTimeout(release, 100); }); // priority=-1; queues first - semaphore.acquire(2, -1).then(([, release]) => { + semaphore.acquire({ priority: -1 }).then(([, release]) => { values.push(-1); setTimeout(release, 100); }); // priority=+1; jumps ahead of priority=-1 - semaphore.acquire(2, +1).then(([, release]) => { + semaphore.acquire({ weight: 1 }).then(([, release]) => { values.push(+1); setTimeout(release, 100); }); @@ -77,8 +78,8 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('acquire allows light high-priority tasks to skip the line', async () => { let executed = false; - semaphore.acquire(3, 0); - semaphore.acquire(1, 1).then(([, release]) => { + semaphore.acquire({ weight: 3, priority: 0 }); + semaphore.acquire({ weight: 1, priority: 1 }).then(([, release]) => { executed = true; setTimeout(release, 100); }); @@ -90,23 +91,23 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => const values: Array = []; // two items with weight 1; runs first because nothing else is waiting - semaphore.acquire(1, 0).then(([, release]) => { + semaphore.acquire({ priority: 0 }).then(([, release]) => { values.push(0); setTimeout(release, 100); }); - semaphore.acquire(1, 0).then(([, release]) => { + semaphore.acquire({ priority: 0 }).then(([, release]) => { values.push(0); setTimeout(release, 100); }); // low-priority item with weight 1 - semaphore.acquire(1, -1).then(([, release]) => { + semaphore.acquire({ priority: -1 }).then(([, release]) => { values.push(-1); setTimeout(release, 100); }); // high-priority item with weight 2; should run before the others - semaphore.acquire(2, +1).then(([, release]) => { + semaphore.acquire({ weight: 2, priority: +1 }).then(([, release]) => { values.push(+1); setTimeout(release, 100); }); @@ -119,7 +120,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => let done = false; async function lightLoop() { while (!done) { - const [,release] = await semaphore.acquire(1); + const [,release] = await semaphore.acquire({ weight: 1 }); await new Promise((resolve) => { setTimeout(resolve, 10); }); release(); } @@ -127,7 +128,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => lightLoop(); await clock.tickAsync(5); lightLoop(); - semaphore.acquire(2).then(() => { done = true; }); + semaphore.acquire({ weight: 2 }).then(() => { done = true; }); await clock.tickAsync(10); await clock.tickAsync(10); assert.strictEqual(done, true); @@ -218,7 +219,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('the releaser increments by the correct weight', async () => { - await semaphore.acquire(2); + await semaphore.acquire({ weight: 2 }); assert.strictEqual(semaphore.getValue(), 0); semaphore.release(2); @@ -308,7 +309,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('runExclusive passes the correct weight', async () => { - semaphore.runExclusive(() => undefined, 2); + semaphore.runExclusive(() => undefined, { weight: 2 }); assert.strictEqual(semaphore.getValue(), 0); await clock.runAllAsync(); @@ -317,9 +318,9 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('runExclusive executes high-priority tasks first', async () => { const values: number[] = []; - semaphore.runExclusive(() => { values.push(0) }, 2); - semaphore.runExclusive(() => { values.push(-1) }, 2, -1); - semaphore.runExclusive(() => { values.push(+1) }, 2, +1); + semaphore.runExclusive(() => { values.push(0) }, { weight: 2 }); + semaphore.runExclusive(() => { values.push(-1) }, { weight: 2, priority: -1 }); + semaphore.runExclusive(() => { values.push(+1) }, { weight: 2, priority: +1 }); await clock.runAllAsync(); assert.deepStrictEqual(values, [0, +1, -1]); }); @@ -367,9 +368,9 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => let flag2 = false; let flag3 = false; - semaphore.acquire(1).then(() => (flag1 = true)); - semaphore.acquire(2).then(() => (flag2 = true)); - semaphore.acquire(4).then(() => (flag3 = true)); + semaphore.acquire({ weight: 1 }).then(() => (flag1 = true)); + semaphore.acquire({ weight: 2 }).then(() => (flag2 = true)); + semaphore.acquire({ weight: 4 }).then(() => (flag3 = true)); semaphore.setValue(3); @@ -382,8 +383,8 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('setValue works fine with isolated weights', async () => { let flag = false; - semaphore.acquire(4).then(() => (flag = true)); - semaphore.acquire(8); + semaphore.acquire({ weight: 4 }).then(() => (flag = true)); + semaphore.acquire({ weight: 8 }); semaphore.setValue(4); await clock.tickAsync(1); @@ -436,7 +437,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('a canceled waiter will not lock the semaphore again', async () => { - const [, release] = await semaphore.acquire(2); + const [, release] = await semaphore.acquire({ weight: 2 }); semaphore.acquire().then(undefined, () => undefined); semaphore.cancel(); @@ -449,7 +450,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('cancel works fine with isolated weights', () => { - const ticket = semaphore.acquire(3); + const ticket = semaphore.acquire({ weight: 3 }); semaphore.cancel(); @@ -514,13 +515,13 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('waitForUnlock only unblocks if the configured weight can be acquired', async () => { - await semaphore.acquire(2); + await semaphore.acquire({ weight: 2 }); let flag1 = false; let flag2 = false; - semaphore.waitForUnlock(1).then(() => (flag1 = true)); - semaphore.waitForUnlock(2).then(() => (flag2 = true)); + semaphore.waitForUnlock({ weight: 1 }).then(() => (flag1 = true)); + semaphore.waitForUnlock({ weight: 2 }).then(() => (flag2 = true)); semaphore.release(1); await clock.tickAsync(0); @@ -533,12 +534,24 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => assert.deepStrictEqual([flag1, flag2], [true, true]); }); + test('waitForUnlock defaults to weight 1', async () => { + let isResolved = false; + semaphore.setValue(0); + semaphore.waitForUnlock({ weight: undefined }).then(() => { isResolved = true; }); + await clock.tickAsync(0); + assert.strictEqual(isResolved, false); + semaphore.release(1); + await clock.tickAsync(0); + assert.strictEqual(isResolved, true); + }); + test('waitForUnlock unblocks only high-priority waiters immediately', async () => { const calledBack: number[] = []; - semaphore.acquire(3, 1); // A big heavy waiting task - semaphore.waitForUnlock(1, 0).then(() => { calledBack.push(0); }); // Low priority - semaphore.waitForUnlock(1, 2).then(() => { calledBack.push(2); }); // High priority - semaphore.waitForUnlock(1, 1).then(() => { calledBack.push(1); }); // Queued behind the heavy task + semaphore.setValue(1); + semaphore.acquire({ weight: 2, priority: 1 }); // A big heavy waiting task + semaphore.waitForUnlock({ weight: 1, priority: 0 }).then(() => { calledBack.push(0); }); // Low priority + semaphore.waitForUnlock({ weight: 1, priority: 2 }).then(() => { calledBack.push(2); }); // High priority + semaphore.waitForUnlock({ weight: 1, priority: 1 }).then(() => { calledBack.push(1); }); // Queued behind the heavy task await clock.runAllAsync(); assert.deepStrictEqual(calledBack, [2]); }); @@ -546,11 +559,12 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('waitForUnlock unblocks waiters of descending priority as the queue drains', async () => { let calledBack = false; let release: SemaphoreInterface.Releaser; + semaphore.setValue(1); - semaphore.acquire(2, 2).then(([, r]) => { release = r; }); - semaphore.acquire(2, 0).then(([, r]) => { setTimeout(r, 100); }); + semaphore.acquire({ priority: 2 }).then(([, r]) => { release = r; }); + semaphore.acquire({ priority: 0 }).then(([, r]) => { setTimeout(r, 100); }); - semaphore.waitForUnlock(2, 1).then(() => { calledBack = true; }); + semaphore.waitForUnlock({ weight: 1, priority: 1 }).then(() => { calledBack = true; }); await clock.tickAsync(0); assert.strictEqual(calledBack, false); @@ -562,14 +576,14 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => test('waitForUnlock resolves immediately when the queue is empty', async () => { let calledBack = false; - semaphore.waitForUnlock(1).then(() => { calledBack = true; }); + semaphore.waitForUnlock({ weight: 1 }).then(() => { calledBack = true; }); await clock.tickAsync(0); assert.strictEqual(calledBack, true); }); test('waitForUnlock only unblocks when the semaphore can actually be acquired again', async () => { - semaphore.acquire(2); - semaphore.acquire(2); + semaphore.acquire({ weight: 2 }); + semaphore.acquire({ weight: 2 }); let flag = false; semaphore.waitForUnlock().then(() => (flag = true)); @@ -586,7 +600,7 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('trying to acquire with a negative weight throws', () => { - assert.throws(() => semaphore.acquire(-1)); + assert.throws(() => semaphore.acquire({ weight: -1 })); }); test('trying to release with a negative weight throws', () => { @@ -594,6 +608,6 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => }); test('trying to waitForUnlock with a negative weight throws', () => { - assert.throws(() => semaphore.waitForUnlock(-1)); + assert.throws(() => semaphore.waitForUnlock({ weight: -1 })); }); }; diff --git a/test/withTimeout.ts b/test/withTimeout.ts index 1603655..9a6c3df 100644 --- a/test/withTimeout.ts +++ b/test/withTimeout.ts @@ -257,7 +257,7 @@ suite('withTimeout', () => { }); test('waitForUnlock times out', async () => { - semaphore.acquire(2); + semaphore.acquire({ weight: 2 }); let state = 'PENDING'; semaphore.waitForUnlock()