Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RangeError: Maximum call stack size exceeded #217

Open
Umdrahschua opened this issue Jan 16, 2025 · 1 comment
Open

RangeError: Maximum call stack size exceeded #217

Umdrahschua opened this issue Jan 16, 2025 · 1 comment

Comments

@Umdrahschua
Copy link

Umdrahschua commented Jan 16, 2025

At the moment I'm testing my project and I run into following error

Exception in PromiseRejectCallback:
file:///MY_PROJECT/node_modules/p-queue/dist/index.js:202
            }, options);
            ^

RangeError: Maximum call stack size exceeded

I add 10,000 tasks and after some seconds I abort all 10,000 tasks and remove them. Then I get the RangeError.

If I look into the code, could it be that there is a recursion (in the case when many tasks have been aborted)?

If I see it correctly, then #next() calls tryToStartAnother() and tryToStartAnother() calls job() and job() has a try-catch block which calls #next() in the finally block.

	#next(): void {
		...
		this.#tryToStartAnother();
		...
	}


	#tryToStartAnother(): boolean {
		...
		if (!this.#isPaused) {
			...
				job();
			...
		}
		...
	}

	async add<TaskResultType>(...): ... {
		...

		return new Promise((resolve, reject) => {
			this.#queue.enqueue(async () => {
				...

				try {
					...
				} catch (error: unknown) {
					...
				} finally {
					this.#next();
				}
			}, options);
			...
	}

Following code demonstrates my issue

import PQueue from 'p-queue';

console.log('Start');

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

for (let i = 0; i < 10000; i++) {
    queue.add(() => { 1 + 1 }, { signal: controller.signal });
}

console.log('Abort');
controller.abort();

// wait for 10 seconds
await new Promise(resolve => setTimeout(resolve, 10000));
console.log('Done waiting');
@Umdrahschua
Copy link
Author

I'm not a Node expert and still try to understand the issue, but I solve this by wrapping function #next() into process.nextTick()...

// index.js
    #next() {
        process.nextTick(() => {
            this.#pending--;
            this.#tryToStartAnother();
            this.emit('next');
        });
    }

...and catching the abort error

queue.add(() => { 1 + 1 }, { signal: controller.signal }).catch(() => {});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant