Skip to content

node:cluster: shared ephemeral port for listen(0) + SCHED_RR fd-passing distribution #4962

@proggeramlug

Description

@proggeramlug

Follow-up to #4914, which ships worker port-sharing via SO_REUSEPORT (kernel-balanced, effectively SCHED_NONE). Two Node-fidelity items were consciously scoped out of that PR:

1. listen(0) — all workers must share ONE primary-assigned ephemeral port

In Node, when a cluster worker calls server.listen(0), the primary binds the ephemeral port once and every worker shares it. With the naive SO_REUSEPORT approach each worker binds its own ephemeral port, so N workers end up on N different ports.

Closing this needs a queryServer-style round-trip over the existing internal NODE_CLUSTER IPC message channel (consume_internal_message in crates/perry-runtime/src/cluster.rs): worker asks primary for the address key, primary binds (or returns the already-bound port), worker then binds that concrete port with SO_REUSEPORT.

2. SCHED_RR — true round-robin handle distribution via fd-passing

Node's default scheduling policy on non-Windows is round-robin: the primary owns the listening socket, accepts connections, and passes each accepted fd to a worker. Perry's fork IPC channel is already a socketpair(2) (UnixStream::pair() in crates/perry-runtime/src/child_process/fork.rs), so SCM_RIGHTS fd-passing is feasible — but it requires a primary-side accept loop, ancillary-data send/recv on the IPC channel, and reconstructing the connection inside the worker's HTTP/net server.

Until then cluster.schedulingPolicy reads as SCHED_RR but actual distribution is kernel SO_REUSEPORT balancing.

Acceptance

  • listen(0) in N workers → all workers report the same server.address().port, primary-coordinated.
  • SCHED_RR policy actually distributes accepted connections round-robin via fd-passing over the fork IPC socketpair.
  • cluster.schedulingPolicy = cluster.SCHED_NONE vs SCHED_RR selects between the two mechanisms.

Metadata

Metadata

Assignees

No one assigned

    Labels

    parityNode.js compatibility / parity gaps

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions