Skip to content

Commit

Permalink
fix: Clear the timer for task timeout after the task has completed
Browse files Browse the repository at this point in the history
  • Loading branch information
katsuya committed Sep 21, 2023
1 parent ec099ac commit 5f3c9cd
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 11 deletions.
24 changes: 15 additions & 9 deletions src/promise-pool-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,21 +543,27 @@ export class PromisePoolExecutor<T, R> 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<void> {
return new Promise<void>((_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>, () => void] {
let timerId: ReturnType<typeof setTimeout> | undefined
const timer: () => Promise<void> = async () =>
new Promise<void>((_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]
}

/**
Expand Down
5 changes: 3 additions & 2 deletions test/promise-pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 5f3c9cd

Please sign in to comment.