Skip to content

node:child_process: honor subprocess.send callback and closed-channel semantics #3316

Description

@andrewtdiz

Summary

fork() now exposes a parent-side subprocess.send(...), but Perry does not match Node's observable optional-argument and closed-channel behavior. In Node, send has the message[, sendHandle[, options]][, callback] shape, invokes the callback when delivery succeeds or fails, and reports closed IPC channels. Perry currently ignores the optional argument slot and returns success regardless of whether the IPC write succeeded.

Node Behavior

Local Node v25.9.0 probe:

const { fork } = require("node:child_process");
const child = fork(childFile, [], { stdio: ["ignore", "ignore", "ignore", "ipc"] });

console.log(child.send.length); // 4
console.log(child.send({ ok: true }, (err) => console.log(err && err.code))); // true, callback gets null
child.disconnect();
console.log(child.send({ after: true }, (err) => console.log(err && err.code))); // false, callback gets ERR_IPC_CHANNEL_CLOSED

The same API also accepts the documented sendHandle and options slots for IPC handle passing / serialization options.

Perry Behavior

Current source evidence:

  • crates/perry-runtime/src/child_process/fork.rs:95 installs send on forked ChildProcess objects as cp_cast2(cp_method_send).
  • crates/perry-runtime/src/child_process/mod.rs:873-882 implements cp_method_send(closure, message, _arg), ignores _arg, never detects a callback/options/sendHandle shape, calls reactor::cp_ipc_send(handle, message), discards that boolean result, and always returns true.
  • crates/perry-runtime/src/child_process/mod.rs:985 registers the method arity as 2, while Node reports child.send.length === 4.
  • crates/perry-runtime/src/child_process/reactor.rs:328-378 can report IPC write failure as false, but the public send method does not surface it or deliver a callback error.
  • Existing closed node:child_process — fork() + IPC (send/disconnect/'message'/channel) unimplemented #1933 covered making parent-side fork IPC exist; it did not track this callback / closed-channel / optional-argument behavior as a remaining leaf.

Suggested PR Cut

Batch this with related issues in:
node:child_process: subprocess lifecycle and setup parity cut

Good batch candidates:

Do not batch with:

  • unrelated modules
  • broad subsystem rewrites
  • spawn/exec option semantics that do not touch IPC delivery
  • fixes needing a compiled-Perry child-process IPC harness unless the PR deliberately includes that harness work

Acceptance

  • parity/regression test proves callback invocation on successful subprocess.send(...)
  • parity/regression test proves a disconnected IPC channel returns false and calls the callback with a Node-shaped ERR_IPC_CHANNEL_CLOSED
  • subprocess.send.length matches Node's observable arity
  • implementation handles or explicitly rejects unsupported sendHandle / options cases with Node-shaped behavior instead of silently ignoring them
  • related known-failure/docs/manifest entries updated if touched

Activity

  1. andrewtdiz commented on Jun 2, 2026

    @andrewtdiz
    ContributorAuthor

    Taking this with #2556 and #2717 as a focused node:child_process lifecycle/IPC surface PR cut. Planned scope: ChildProcess Symbol.dispose dispatch, _forkChild enumerable export shape, and subprocess.send callback/closed-channel observable semantics. Non-goals: broad spawn/exec option semantics (#2555), setup arg validation (#3079), and child-side process IPC surface (#2529) unless a minimal helper is required for the selected tests.

  2. andrewtdiz commented on Jun 2, 2026

    @andrewtdiz
    ContributorAuthor

    Implemented in draft PR #4110.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions