Skip to content

[Node] Spawn the native sandbox off the JavaScript thread - #1354

Merged
Soham Das (SohamDas2021) merged 1 commit into
mainfrom
sohamdas2021-1291-pr5
Oct 2, 2026
Merged

Soham Das (SohamDas2021) merged 1 commit into
mainfrom
sohamdas2021-1291-pr5

Conversation

@SohamDas2021

@SohamDas2021 Soham Das (SohamDas2021) commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Moves mxc_spawn_request onto koffi .async so a slow native spawn can't block Node's event loop.

LXC preparation downloads a container image and waits for a DHCP lease, so with LXC streaming now merged (#1333) that call can occupy the JavaScript thread for tens of seconds. wait and free already used .async; spawn did not.

Scope reduced after review. This PR originally also added a containment option to spawnSandbox/spawnSandboxAsync. Per Branden Bonaby (@bbonaby), those APIs are being replaced by the new public surface and callers will pass the config directly, so that half was dropped rather than churn an API that is going away. What remains is the internal FFI binding, which the new spawn/spawnWithPty entry points will route through.

Also corrects a stale README claim that the abstract process intent resolves to lxc on Linux; it resolves to Bubblewrap.

Testing: no CI lane exercises this path — MXC_SKIP_OS_BUILD_DEPENDENT_TESTS skips the native-streaming suite on all four sdk-integration-tests lanes, and the unit tests run against a fake native layer. Validated locally against a real mxc_ffi build on Windows/Node 24 (both native-streaming cases pass), plus unit coverage for off-thread dispatch, out-of-order concurrent spawns, and error mapping.

This can merge independently. It targets main and no longer shares any file with the rest of the stack beyond the await fixups in sdk/node/tests/integration/native-streaming.test.ts, which sit on top of #1333 as merged.

Microsoft Reviewers: Open in CodeFlow

@SohamDas2021
Soham Das (SohamDas2021) requested review from a team and a balanced review from Copilot September 30, 2026 18:35
@SohamDas2021
Soham Das (SohamDas2021) requested a review from a team as a code owner September 30, 2026 18:35
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The narrowed config-spawn overload breaks an existing typed caller and the TypeScript test build.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Adds explicit containment selection to Node SDK convenience APIs and moves native streaming spawn work off the event loop.

Changes:

  • Adds containment spawn options and validation.
  • Makes native streaming spawn asynchronous.
  • Expands documentation and tests for backend routing and ownership.
File Description
sdk/​node/​src/​sandbox.ts Adds containment selection and config-option validation.
sdk/​node/​src/​index.ts Exports the new options type.
sdk/​node/​src/​state-aware.ts Rejects containment options for state-aware APIs.
sdk/​node/​src/​bindings/​streaming.ts Moves native spawn to Koffi async invocation.
sdk/​node/​README.md Documents backend selection and errors.
sdk/​node/​tests/​unit/​streaming-binding.test.ts Tests asynchronous spawn and ownership.
sdk/​node/​tests/​unit/​state-aware.test.ts Tests unsupported containment options.
sdk/​node/​tests/​unit/​sandbox.test.ts Tests convenience-path routing.
sdk/​node/​tests/​unit/​inprocess-run.test.ts Tests in-process containment selection.
sdk/​node/​tests/​unit/​binding-request.test.ts Tests supported native containments.
sdk/​node/​tests/​integration/​native-streaming.test.ts Awaits asynchronous native streaming spawn.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sdk/node/src/sandbox.ts Outdated
Copilot AI balanced review requested due to automatic review settings September 30, 2026 18:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The new config-spawn overload breaks integration typechecking, and the concurrent-handle test does not validate handle identity.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Use handle-specific IDs to validate completion handle ownership

sdk/​node/​tests/​unit/​streaming-binding.test.ts:486

This test does not verify that each completion adopts its own handle: FakeNative.id() always returns 23 and free() only increments a counter, so both promises could accidentally adopt the first handle and every assertion would still pass. Make the fake return a handle-specific ID so this test actually catches shared/out-of-order out-parameter bugs.

Copilot AI balanced review requested due to automatic review settings September 30, 2026 19:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The public option documentation incorrectly promises identical backend support across both convenience APIs.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Document microvm exception in spawnSandboxAsync containment contract

sdk/​node/​src/​sandbox.ts:655

This IntelliSense contract overstates parity: spawnSandboxAsync still rejects microvm, while spawnSandbox can launch the generated MicroVM config through the executor (the README now documents this exception at lines 307–313). Please include that exception here so callers do not infer that every typed containment value behaves identically on both APIs.

@SohamDas2021 Soham Das (SohamDas2021) changed the title [LXC] (5/5) Let the Node SDK select a containment backend in-process [LXC] (5/5) Enable Node SDK select a containment backend in-process Sep 30, 2026
Comment thread sdk/node/src/sandbox.ts Outdated
Comment thread sdk/node/README.md Outdated
Copilot AI balanced review requested due to automatic review settings October 1, 2026 23:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The README incorrectly advertises MicroVM support while omitting several supported high-level backends.

Review effort: Balanced
Findings: 1 Low severity

Open (1)

Comment thread sdk/node/README.md Outdated
Copilot AI balanced review requested due to automatic review settings October 1, 2026 23:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The primary in-process LXC execution path lacks integration coverage through the public API.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Add Linux/LXC integration coverage for public spawnSandboxAsync API

sdk/​node/​tests/​unit/​inprocess-run.test.ts:150

This only verifies request projection because capture replaces the native implementation. The existing Linux LXC integration helper (tests/integration/linux-process-container.test.ts:39-47) still executes through spawnSandboxFromConfig, so the PR's main behavior—spawnSandboxAsync(..., { containment: 'lxc' }) actually reaching and running LXC in-process—has no integration coverage. Add a Linux/LXC-gated integration case that invokes this public API and asserts the backend identity.

Comment thread sdk/node/README.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The advertised in-process LXC path lacks native integration coverage.

Review effort: Balanced
Findings: None

Previously missed (1)

In code that hasn't changed since last review

Medium severity Add LXC integration coverage for in-process spawn routing

sdk/​node/​src/​sandbox.ts:780

The new in-process LXC path is only covered with _setBindingRunAsyncImplementation, so the native call is replaced before mxc_run_request or LXC runs. The existing LXC integration suite still uses spawnSandboxFromConfig through the executor, leaving the PR's main routing path unverified. Add a Linux integration case that calls spawnSandboxAsync(..., { containment: 'lxc' }) and checks the backend fingerprint.

Comment thread sdk/node/src/sandbox.ts Outdated
Comment thread sdk/node/src/sandbox.ts Outdated
Comment thread sdk/node/src/sandbox.ts Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f3216a57-02e3-483e-94f6-90a2ff877662
Copilot AI balanced review requested due to automatic review settings October 2, 2026 04:59
@SohamDas2021 Soham Das (SohamDas2021) changed the title [LXC] (5/5) Enable Node SDK select a containment backend in-process [Node] Spawn the native sandbox off the JavaScript thread Oct 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The tests do not currently verify the actual Koffi async boundary or distinguish concurrent native handles.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)

assert.strictEqual(native.freeCount, 0);
});

it('spawns off-thread so the event loop keeps running', async () => {
@SohamDas2021
Soham Das (SohamDas2021) merged commit 702610f into main Oct 2, 2026
31 checks passed
@SohamDas2021
Soham Das (SohamDas2021) deleted the sohamdas2021-1291-pr5 branch October 2, 2026 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants