diff --git a/src/promise-pool-executor.ts b/src/promise-pool-executor.ts index c1bed5c..b002450 100644 --- a/src/promise-pool-executor.ts +++ b/src/promise-pool-executor.ts @@ -543,21 +543,27 @@ export class PromisePoolExecutor implements UsesConcurrency, Stoppable, St return this.handler(item, index, this) } + const [timer, canceller] = this.createTaskTimeout(item) return Promise.race([ this.handler(item, index, this), - this.createTaskTimeout(item) - ]) + timer(), + ]).finally(canceller) } /** - * Returns a promise that times-out after the configured task timeout. + * Returns a tuple of a timer function and a canceller function that + * times-out after the configured task timeout. */ - private async createTaskTimeout (item: T): Promise { - return new Promise((_resolve, reject) => { - setTimeout(() => { - reject(new PromisePoolError(`Promise in pool timed out after ${this.taskTimeout() as number}ms`, item)) - }, this.taskTimeout()) - }) + private createTaskTimeout (item: T): [() => Promise, () => void] { + let timerId: ReturnType | undefined + const timer: () => Promise = async () => + new Promise((_resolve, reject) => { + timerId = setTimeout(() => { + reject(new PromisePoolError(`Promise in pool timed out after ${this.taskTimeout() as number}ms`, item)) + }, this.taskTimeout()) + }) + const canceller: () => void = () => clearTimeout(timerId) + return [timer, canceller] } /** diff --git a/test/promise-pool.js b/test/promise-pool.js index d5af5f4..e1bbb67 100644 --- a/test/promise-pool.js +++ b/test/promise-pool.js @@ -630,19 +630,20 @@ test('useCorrespondingResults defaults results to notRun symbol', async () => { test('can timeout long-running handlers', async () => { const timers = [1, 2, 3, 4] + const leeway = 5 const { results, errors } = await PromisePool .withTaskTimeout(10) .for(timers) .process(async (timer) => { - const computed = 10 * timer + const computed = 10 * timer - leeway await pause(computed) return computed }) // only the first item resolves - expect(results).toEqual([10]) + expect(results).toEqual([5]) // items 2, 3, and 4 time out expect(errors.length).toEqual(3)