Skip to content
advanced

Review: the queue that stalls after a failure

This is recall. The code looks finished and is wrong. Find the defect and fix it. You are graded on tests you cannot see.

You need to run slow jobs without melting the database, so you write a queue that keeps at most `limit` tasks running at once. It looks right, its own tests pass, and it survives a week of traffic.

export type Task = () => Promise<void>

export class TaskQueue {
  #waiting: Array<() => void> = []
  #active = 0
  readonly #limit: number

  constructor(limit: number) {
    this.#limit = limit
  }

  run(task: Task): Promise<void> {
    return new Promise((resolve, reject) => {
      const start = () => {
        this.#active += 1
        task()
          .then((result) => {
            resolve(result)
            this.#active -= 1
            this.#drain()
          })
          .catch((error: unknown) => {
            reject(error)
          })
      }

      if (this.#active < this.#limit) start()
      else this.#waiting.push(start)
    })
  }

  #drain(): void {
    while (this.#active < this.#limit && this.#waiting.length > 0) {
      this.#waiting.shift()?.()
    }
  }
}
review — find the defectCtrl+↵ submits · Ctrl+Shift+↵ runsstarter code