Skip to content

node:process: implement child-side IPC channel surface #2529

Closed

Description

@andrewtdiz

Summary

Perry still needs the child-side process IPC surface when a compiled Perry program is launched with a Node-style IPC channel (NODE_CHANNEL_FD).

The parent-side child_process.fork() IPC work landed in #1955/#1933, but that PR explicitly called out the compiled-Perry child side as a remaining follow-up. Today the lowering path appears to treat process.send, process.disconnect, and process.connected as unconditionally undefined, which matches a normal non-IPC process but cannot support a Perry child process inheriting fd 3.

Evidence

  • docs/runtime-parity.md:2275-2279 lists process.send, process.disconnect, process.channel, process.channel.ref(), and process.channel.unref() as public Node process IPC APIs.
  • docs/runtime-parity-gaps.md:635-639 keeps the same process IPC rows in the gap list.
  • crates/perry-hir/src/lower/expr_member.rs short-circuits process.send, process.disconnect, and process.connected to undefined for ordinary process member reads.
  • crates/perry-runtime/src/child_process/fork.rs launches forked children with NODE_CHANNEL_FD=3 so Node children get process.send / process.on("message") automatically, but this does not install the same surface for a compiled Perry child.
  • PR feat(node:child_process): async spawn reactor, fork()+IPC, exec error/encoding parity (#1933–#1938) #1955 says the remaining follow-up is the child-side process.send / process.on('message') behavior when a compiled-Perry binary is itself the fork target.

Expected behavior

When a Perry process starts with a valid Node-style IPC channel, it should expose Node-compatible child-side IPC APIs:

  • process.send(message[, sendHandle[, options]][, callback]) serializes messages to the parent.
  • process.on("message", handler) receives parent messages.
  • process.disconnect() closes the IPC channel and updates state.
  • process.connected reflects channel state.
  • process.channel exposes the channel object, including ref() / unref().
  • In a normal non-IPC process, these members should continue to match Node's non-IPC shape.

Duplicate check

I searched issues and PRs for compiled Perry child process.send NODE_CHANNEL_FD process.on message and process.send NODE_CHANNEL_FD process.channel compiled. The only related result is merged PR #1955 / closed #1933 for parent-side child_process.fork() IPC, and that PR explicitly leaves this compiled-child-side behavior as follow-up work.

Verification note

I do not have a local perry binary in this checkout, so this is based on committed parity docs/tests, source search, and the #1955 PR notes rather than a fresh runtime comparison.

Activity

  1. andrewtdiz commented on Jun 3, 2026

    @andrewtdiz
    ContributorAuthor

    I’m taking this as a focused node:process child-side IPC parity cut.

    Intended PR scope: detect an inherited NODE_CHANNEL_FD channel in a compiled Perry child, expose the IPC-only process.send, process.disconnect, process.connected, and process.channel surface only while that channel exists, deliver JSON IPC messages through process.on("message"), and cover process.channel.ref() / unref() shape/active-handle behavior at a deterministic level.

    Non-goals: socket/handle passing, serialization: "advanced" child-side framing, broad parent-side child_process.fork() changes, and unrelated process APIs.

  2. andrewtdiz commented on Jun 3, 2026

    @andrewtdiz
    ContributorAuthor

    Draft PR opened for this child-side IPC cut: #4207

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