Repository: nodejs/node
Pull request: lib: disable default memory leak warning for AbortSignal

This change sets the default `kMaxEventTargetListeners` property for `AbortSignal` instances to 0, disabling the check per default, to enable users to write isomorphic library code.
If desirable, the max event target listeners check can still be enabled for individual `AbortSignal` instances by calling `setMaxListeners` on them.

Refs: https://github.com/nodejs/node/issues/54758

<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


I ran all the test I believe are relevant locally, but I can't run the full test suite as I'm working on a managed Mac and can't change firewall rules, so the test suite just explodes on me with popups.

Changed files:
filename: doc/api/events.md
patch: @@ -1171,6 +1171,10 @@ that a "possible EventEmitter memory leak" has been detected. For any single
 `EventEmitter`, the `emitter.getMaxListeners()` and `emitter.setMaxListeners()`
 methods can be used to temporarily avoid this warning:
 
+`defaultMaxListeners` has no effect on `AbortSignal` instances. While it is
+still possible to use [`emitter.setMaxListeners(n)`][] to set a warning limit
+for individual `AbortSignal` instances, per default `AbortSignal` instances will not warn.
+
 ```mjs
 import { EventEmitter } from 'node:events';
 const emitter = new EventEmitter();

filename: lib/internal/abort_controller.js
patch: @@ -28,6 +28,7 @@ const {
   kResistStopPropagation,
   kWeakHandler,
 } = require('internal/event_target');
+const { kMaxEventTargetListeners } = require('events');
 const {
   customInspectSymbol,
   kEmptyObject,
@@ -164,6 +165,7 @@ class AbortSignal extends EventTarget {
     }
     super();
 
+    this[kMaxEventTargetListeners] = 0;
     const {
       aborted = false,
       reason = undefined,

filename: test/parallel/test-eventtarget-memoryleakwarning.js
patch: @@ -12,22 +12,22 @@ const { setTimeout } = require('timers/promises');
 common.expectWarning({
   MaxListenersExceededWarning: [
     ['Possible EventTarget memory leak detected. 3 foo listeners added to ' +
-     'EventTarget. MaxListeners is 2. Use events.setMaxListeners() ' +
+        'EventTarget. MaxListeners is 2. Use events.setMaxListeners() ' +
      'to increase limit'],
     ['Possible EventTarget memory leak detected. 3 foo listeners added to ' +
-     '[MessagePort [EventTarget]]. ' +
-     'MaxListeners is 2. ' +
-     'Use events.setMaxListeners() to increase ' +
+        '[MessagePort [EventTarget]]. ' +
+        'MaxListeners is 2. ' +
+        'Use events.setMaxListeners() to increase ' +
      'limit'],
     ['Possible EventTarget memory leak detected. 3 foo listeners added to ' +
-     '[MessagePort [EventTarget]]. ' +
-     'MaxListeners is 2. ' +
-     'Use events.setMaxListeners() to increase ' +
+        '[MessagePort [EventTarget]]. ' +
+        'MaxListeners is 2. ' +
+        'Use events.setMaxListeners() to increase ' +
      'limit'],
-    ['Possible EventTarget memory leak detected. 3 foo listeners added to ' +
-     '[AbortSignal]. ' +
-     'MaxListeners is 2. ' +
-     'Use events.setMaxListeners() to increase ' +
+    ['Possible EventTarget memory leak detected. 2 foo listeners added to ' +
+        '[AbortSignal]. ' +
+        'MaxListeners is 1. ' +
+        'Use events.setMaxListeners() to increase ' +
      'limit'],
   ],
 });
@@ -65,13 +65,25 @@ common.expectWarning({
   mc.port1.addEventListener('foo', () => {});
   mc.port1.addEventListener('foo', () => {});
   mc.port1.addEventListener('foo', () => {});
+}
 
+{
+  // No warning emitted because AbortController ignores `EventEmitter.defaultMaxListeners`
+  setMaxListeners(2);
   const ac = new AbortController();
   ac.signal.addEventListener('foo', () => {});
   ac.signal.addEventListener('foo', () => {});
   ac.signal.addEventListener('foo', () => {});
 }
 
+{
+  // Will still warn as `setMaxListeners` can still manually set a limit
+  const ac = new AbortController();
+  setMaxListeners(1, ac.signal);
+  ac.signal.addEventListener('foo', () => {});
+  ac.signal.addEventListener('foo', () => {});
+}
+
 {
   // It works for EventEmitters also
   const ee = new EventEmitter();