[APPS-2792] Prototype: local Node execution for backend functions - #461
Conversation
b5df661 to
ecd1ea2
Compare
Adds a Mode-A local execution path for *.backend.ts functions, parallel to executeScriptViaDatadog (dev-server.ts): a child_process.fork()'d child runs the real bundled script, with $.Actions calls proxied back over the fork's built-in IPC channel to the parent. Not wired into createDevServerMiddleware. executeActionRemotely is a stub for the single-action execution capability that doesn't exist yet (see the design doc's Open Dependency section) -- this is an early prototype for design-doc discussion, not ready to ship. The $.Actions Proxy get/apply logic in local-exec-child.js is a direct Node port of the actionplatform Deno script template's makeActionsProxy (dd-source), which has zero Deno dependencies and copies over verbatim. local-execution.integration.test.ts is a real, unmocked integration test: real vite.build(), real getBaseBackendBuildConfig, real generateDevVirtualEntryContent, against a real *.backend.ts fixture on disk -- not hand-written stand-ins. Full design doc: .plans/high-code-apps-local-node-execution-design.md (dd-source, not yet published to Confluence). Co-Authored-By: Claude <noreply@anthropic.com>
ecd1ea2 to
fbb6773
Compare
|
Superseded: a team sync (2026-08-04, Terrapin) decided to drop This PR's fork/IPC skeleton and message protocol don't apply to the new in-process model. Likely salvageable for the reimplementation: the $.Actions Proxy's shape (nested-property-path walk → {fqn, inputs, connectionId}), reworked as a direct in-process call instead of an IPC round trip. The native-module compatibility matrix and latency benchmarks from this PR's testing remain useful reference data even though the mechanism they measured is being replaced. Closing, not deleting the branch, in case anything needs to be referenced later. |
ssr:truefix this prototype's own test depends on).Motivation
npm run devbundles*.backend.tsfunctions locally today, but executes them by round-tripping 100% of the work to Datadog's cloud (preview-async+ long-poll). No Deno or Node runtime executes the function on the developer's machine. Worst case (a hanging function) takes up to ~5 minutes before timing out.console.logback to the developer today requires the full cloud-side round trip to complete first — no real-time feedback.npm/Vite; a local execution mode avoids requiring a second (Deno) runtime install.Architecture
Full design doc, including the execution-model tradeoff analysis (
child_process.fork()vsworker_threads, empirically measured — see QA below), sandboxing, secrets handling, backward compatibility plan, and timeline:.plans/high-code-apps-local-node-execution-design.md(dd-source repo, not yet published to Confluence).Changes
$.Actionscalls back to the parentpackages/plugins/apps/src/vite/local-execution.ts$.ActionsProxy logic from the actionplatform Deno script templatepackages/plugins/apps/src/vite/local-exec-child.jsvite.build(), actualgetBaseBackendBuildConfig/generateDevVirtualEntryContent, against a real.backend.tsfixture on diskpackages/plugins/apps/src/vite/local-execution.integration.test.tsNot included: wiring into
createDevServerMiddleware— this prototype validates the execution mechanics only, deliberately not touching the real request path yet.QA Instructions
Real, measured latency numbers (from a separate throwaway benchmark harness, not part of this PR's test suite — 50 iterations):
child_process.fork()p50/p95/p99 = 36.0/37.3/40.4ms vs.worker_threads= 10.0/10.5/13.2ms. Both dramatically faster than today's multi-second-to-multi-minute cloud round trip regardless of which wins; see the design doc's Execution Model section for the full tradeoff discussion (this PR usesfork(), but that choice isn't fully closed out yet).Manual QA — not yet possible, and that's expected
No manual local or staging QA for this PR specifically:
createDevServerMiddlewaredoesn't call anything in this file, so there's nonpm run devrequest path that reachesexecuteScriptLocally()today — nothing a human can click through yet, on any environment. The integration test above is the closest thing to manual QA currently possible: it exercises the real bundler and a real forked child process end-to-end, not mocked. Real local + staging manual QA becomes possible once Milestone 2 (handleExecuteActionintegration, tracked in a follow-up PR) actually wires this into the dev server.Blast Radius
createDevServerMiddlewareis unmodified, sonpm run dev's actual behavior is unchanged by this PR.Out of Scope / Follow-ups
createDevServerMiddleware/handleExecuteActionexecuteActionRemotelyis currently a stub)/api/unstable/actions/executeendpoint (verified directly inactions-api's code), or (B) ddoghq/dd-source#34887's newexecute_actionMCP tool (draft, Tiffany already collaborating with the author) — see design doc's "Open Dependency" section for the full comparisonchild_process.fork()vsworker_threadsdecisionrequire(), across a bigger package set) before locking this inDocumentation