Skip to content

Commit 5c1de24

Browse files
authored
fix: debounce queue idle/empty events (#3103)
Browsers and Node.js handle resuming control from `yield` slightly differently - a queue that empties in browsers can end up repeating it's idle even when a new job is being added so debounce the call to trigger after a (very) short time has passed.
1 parent a01606e commit 5c1de24

File tree

2 files changed

+30
-10
lines changed

2 files changed

+30
-10
lines changed

packages/utils/src/queue/index.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AbortError, TypedEventEmitter } from '@libp2p/interface'
22
import { pushable } from 'it-pushable'
33
import { raceEvent } from 'race-event'
4+
import { debounce } from '../debounce.js'
45
import { QueueFullError } from '../errors.js'
56
import { Job } from './job.js'
67
import type { AbortOptions, Metrics } from '@libp2p/interface'
@@ -149,22 +150,33 @@ export class Queue<JobReturnType = unknown, JobOptions extends AbortOptions = Ab
149150

150151
this.sort = init.sort
151152
this.queue = []
153+
154+
this.emitEmpty = debounce(this.emitEmpty.bind(this), 1)
155+
this.emitIdle = debounce(this.emitIdle.bind(this), 1)
156+
}
157+
158+
emitEmpty (): void {
159+
if (this.size !== 0) {
160+
return
161+
}
162+
163+
this.safeDispatchEvent('empty')
164+
}
165+
166+
emitIdle (): void {
167+
if (this.running !== 0) {
168+
return
169+
}
170+
171+
this.safeDispatchEvent('idle')
152172
}
153173

154174
private tryToStartAnother (): boolean {
155175
if (this.size === 0) {
156-
// do this in the microtask queue so all job recipients receive the
157-
// result before the "empty" event fires
158-
queueMicrotask(() => {
159-
this.safeDispatchEvent('empty')
160-
})
176+
this.emitEmpty()
161177

162178
if (this.running === 0) {
163-
// do this in the microtask queue so all job recipients receive the
164-
// result before the "idle" event fires
165-
queueMicrotask(() => {
166-
this.safeDispatchEvent('idle')
167-
})
179+
this.emitIdle()
168180
}
169181

170182
return false

packages/utils/test/queue.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ describe('queue', () => {
340340
expect(queue).to.have.property('size', 0)
341341
expect(queue).to.have.property('queued', 0)
342342
expect(queue).to.have.property('running', 0)
343+
344+
await delay(10)
345+
343346
expect(timesCalled).to.equal(1)
344347

345348
const job3 = queue.add(async () => delay(100))
@@ -356,6 +359,8 @@ describe('queue', () => {
356359
expect(queue).to.have.property('queued', 0)
357360
expect(queue).to.have.property('running', 0)
358361

362+
await delay(10)
363+
359364
expect(timesCalled).to.equal(2)
360365
})
361366

@@ -392,6 +397,9 @@ describe('queue', () => {
392397
expect(queue).to.have.property('size', 0)
393398
expect(queue).to.have.property('queued', 0)
394399
expect(queue).to.have.property('running', 0)
400+
401+
await delay(10)
402+
395403
expect(timesCalled).to.equal(1)
396404
})
397405

0 commit comments

Comments
 (0)