sindresorhus / p-queue

Promise queue with concurrency control
MIT License
3.39k stars 182 forks source link

Aborting pending and waiting tasks at the same time hangs the queue #168

Closed klimashkin closed 1 year ago

klimashkin commented 1 year ago

If we have one pending and one waiting task and abort them both, then the queue gets stuck with one pending task forever and gets blocked

import PQueue, {AbortError} from 'p-queue';

const queue = new PQueue({concurrency: 1});

const controller1 = new AbortController();
const controller2 = new AbortController();

try {
    const task1 = queue.add(({signal}) => fetch('https://sindresorhus.com', {signal}), {signal: controller1.signal});
    const task2 = queue.add(({signal}) => fetch('https://example.com', {signal}), {signal: controller2.signal});

          setTimeout(() => {
                  controller1.abort();
                  controller2.abort();

                  queue; // Size: 1  Pending: 1
          }, 0)

        await task1;
        await task2;
} catch (error) {
    if (!(error instanceof AbortError)) {
        throw error;
    }
}
sindresorhus commented 1 year ago

// @Richienb

Richienb commented 1 year ago

I believe a robust solution will be to properly implement a way to dequeue items which will be a breaking change. Similar to https://github.com/sindresorhus/p-queue/issues/140

klimashkin commented 1 year ago

That is a blocker for everyone using a signal in .add

The workaround is to manually check for the aborted signal at the beginning of the task, something like

.add(() => {
    if (controller.signal.aborted) {
      throw new AbortError('The task was aborted.');
    }

    ...
})
Rotemy commented 1 year ago

I think that the main reason is that aborted tasks that are not currently executing, will move and stuck on pending state.

rajsync commented 1 year ago

Any plan for release?