◐ Shell
clean mode source ↗

sockets no longer emit `removeListener` events in v20.11.0

Version

No response

Platform

macos, although I'd be surprised if this issue is platform-specific.

Subsystem

No response

What steps will reproduce the bug?

Here's a reproduction script:

const assert = require('assert');
const { once } = require('events');
const { Server, Socket } = require('net');

async function main() {
  const server = new Server();

  server.on('connection', conn => {
    conn.on('data', () => {
      // do nothing
    });
  });

  server.listen('8000');

  const socket = new Socket();
  await socket.connect({
    host: 'localhost',
    port: '8000'
  });

  const removedListeners = [];
  socket.on('removeListener', name => removedListeners.push(name));

  // write a large buffer to ensure that the socket buffers the data, forcing the drain event
  const buffer = Buffer.alloc(10 * (2 ** 10) ** 2);
  socket.write(buffer);

  const drainEvent = once(socket, 'drain');
  try {
    await drainEvent;
  } finally {
    assert.ok(removedListeners.includes('drain'));
  }
}

main().then(() => process.exit());

This passes on <Node 20.11.0, but fails on any newer version.

How often does it reproduce? Is there a required condition?

Every time.

What is the expected behavior? Why is that the expected behavior?

I'd expect to see a removeListener event emitted for drain (and other events) on the socket, because the once helper resolves, which indicates that we have received a drain event.

What do you see instead?

No removeListener event is emitted.

Additional information

No response