nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨
https://nodejs.org
Other
106.7k stars 29.1k forks source link

Expose `setMaxListeners` property on `AbortSignal` #54758

Open phryneas opened 2 weeks ago

phryneas commented 2 weeks ago

What is the problem this feature will solve?

Right now, there is no stable way to change the maxEventTargetListeners of an AbortSignal without importing from node:events.

This makes it impossible to write isomorphic library code that adds more than the default 10 event listeners, without having to resort to workarounds such as

/**
 * A workaround to set the `maxListeners` property of a node EventEmitter without having to import
 * the `node:events` module, which would make the code non-portable.
 */
function setMaxListeners(maxListeners: number, emitter: any) {
  const key = Object.getOwnPropertySymbols(new AbortController().signal).find(
    (key) => key.description === "events.maxEventTargetListeners"
  );
  if (key) emitter[key] = maxListeners;
}

This relies on the events.maxEventTargetListeners symbol description, which, to my knowledge is not part of any public API and could change at any time.

What is the feature you are proposing to solve the problem?

Add a AbortSignal.setMaxListeners instance method so isomorphic code could do something like

if ('setMaxListeners' in signal) signal.setMaxListeners(20)

What alternatives have you considered?

Alternatively, if this is not an option as it could pollute a spec-defined object with additional properties, use Symbol.for instead of new Symbol for kMaxEventTargetListeners and make that a part of the official api.


I would be willing to implement this feature.

mcollina commented 2 weeks ago

The right avenue to purse this change is WHATWG (the group maintaining those standards). From past experience, any time we deviate from the standard we cause more harm than good.

phryneas commented 2 weeks ago

But isn't maxEventTargetListeners in itself - a limit on the number of listeners and issuing a warning - already a node-only deviation from the standard?

So this would try to explore a way to get closer to the standard, not further away.

phryneas commented 2 weeks ago

By that logic, another alternative suggestion here could be:

Alternative suggestion: set no default listener count limit on AbortController

On all newly created AbortSignal instances, set the kMaxEventTargetListeners to 0 by default to align with standard behaviour - users that want a limit on event listeners can still use setMaxListeners to set a specific limit.

In the research before opening this ticket, I've seen a lot of instances where people were getting this warning with undici fetch, so this seems to be a somewhat common problem.

In my case, this is ironically caused because I want to pass an AbortSignal as the signal option to a lot of addEventListener calls so I can make sure to clean them up.

Either way, it seems that AbortSignal is just made to be reused by many fetch calls or addEventListener calls, so the current limit of 10 is easily reached by normal intended usage (and afaik not to spec).

mcollina commented 2 weeks ago

@jasnell you added the warning in https://github.com/nodejs/node/pull/36001

@KhafraDev you added those getters/setters in https://github.com/nodejs/node/pull/47039

What do you folks think?

KhafraDev commented 2 weeks ago

node shouldn't have implemented warnings or interop with EventEmitter in the first place, but we absolutely shouldn't deviate further from the spec and other implementations

mcollina commented 2 weeks ago

@nodejs/web-standards what do you all think?

mcollina commented 2 weeks ago

Pinging @lucacasonato too (hope you don't mind).

lucacasonato commented 2 weeks ago

Agree with @KhafraDev. If anything this should be a setter function you import from node:events that you pass the signal to as the first argument.

jasnell commented 2 weeks ago

I agree. We should not extend the standard API with non-standard extensions.

ljharb commented 2 weeks ago

+1 (no nonstandard extensions). I do like the alternative suggestion tho (https://github.com/nodejs/node/issues/54758#issuecomment-2328459853)

benjamingr commented 2 weeks ago

I agree with the alternative suggestion as well

mcollina commented 2 weeks ago

@jasnell are you ok for https://github.com/nodejs/node/issues/54758#issuecomment-2328459853?

benjamingr commented 2 weeks ago

Just so we're clear - we are within our rights from the spec's PoV to emit a warning on more than N listeners (or really anything, warnings aren't considered observable). We've clarified that several times with WHATWG explicitly to make sure.

jasnell commented 2 weeks ago

I actually prefer that warning remain in place as it has actually proved useful in a couple of cases. But I won't block removing it.