Skip to content

[rushd][WS2] Daemon host, routing & scheduling #5897

Description

Build the long-lived per-workspace daemon: a warm WorkspaceSession (config + all-projects graph + watcher + plugins) that routes phased and global commands with per-request cwd/env/terminal context, matches in-process exit-code / warnings-as-errors semantics, and forwards stdin/raw-mode for interactive commands. It also serializes and merges concurrent client requests via exclusivity classes, queue-and-wait admission, and shared-build merging instead of failing on 'another rush is running'.

Depends on: #5895; #5896

Scope

  • Scaffold @rushstack/rush-daemon + serve. Launched by the version-selected rush-lib; boots a transport listener and signals readiness.
  • Warm WorkspaceSession. A warm RushConfiguration + all-projects OperationGraph + plugins + inputs snapshot + a long-lived ProjectWatcher that keeps invalidating operations even with no client attached.
  • Phased request routing. Map the selection via setEnabledStates, reconcile pending watcher invalidations, subscribe the client to its operations' raw streams + events, schedule/execute one iteration, and translate final status → exit code.
  • Per-request global-command context. Run global CLI actions with the client's cwd/env/terminal injected per request (never via global process.chdir or shared process.env mutation).
  • Exit-code parity. Match in-process exactly, including the SuccessWithWarning path (stderr-with-exit-0 → warnings, honoring allowWarningsInSuccessfulBuild/RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD).
  • Interactive I/O. Forward stdin bytes + raw-mode/resize control frames; classify PTY-only commands never-daemonize (run in-process on the client).
  • RequestScheduler. Exclusivity classes SHARED-BUILD/SHARED-READ/EXCLUSIVE + a static command-classification table; queue-and-wait admission (FIFO, an EXCLUSIVE "gate", queued-position progress events, clean Ctrl+C, --wait-timeout/--no-wait).
  • Shared-build merging. Union concurrent clients' enabled sets into one iteration, while each client's exit code reflects only its own subset.

Acceptance criteria

  • serve starts a listener at the workspace transport path and signals readiness; a ping control frame returns a pong (carrying protocol + daemon version); the entrypoint is launched via the version-selected rush-lib.
  • On start the session loads config once and builds the all-projects graph + plugins + inputs snapshot; a file change with no client connected marks the correct operations dirty (headless watcher); config/graph are reused across requests (no rebuild).
  • A rush build --to X request enables X's subtree, runs one iteration, and returns the same result set as in-process; a no-op follow-up collapses to a warm skip; the client receives only its selected operations' streams/events and the correct exit code.
  • A global command observes the client's cwd/env while the daemon's own process.cwd()/process.env stay unchanged; two concurrent global commands from different cwds/envs do not cross-contaminate.
  • Success, SuccessWithWarning, and failure cases each return the same exit code as in-process, including under the warnings-as-errors settings/env (table-driven parity test).
  • stdin bytes and raw-mode toggles forward correctly (an interactive prompt behaves identically to in-process); PTY-only commands are on the never-daemonize list and transparently run in-process.
  • Every built-in command has an exclusivity class (unclassified/global default EXCLUSIVE); the scheduler admits compatible classes concurrently and serializes incompatible ones; an EXCLUSIVE request gates later admissions until it finishes; --wait-timeout expires with the documented exit code and --no-wait fails fast.
  • Two overlapping SHARED-BUILD selections run as one merged iteration (shared operations execute once), a failure in one client's subset does not fail another's succeeding subset, and each client gets only its subset's streams/events and a correct exit code.
  • All new daemon behavior ships opt-in until cutover; unit/integration tests green in CI.

Part of #5894.

Activity

  1. dmichon-msft commented on Jul 22, 2026

    @dmichon-msft
    Contributor

    Open questions:

    • Interaction with plugins that modify the shape of the build graph in a way distinct from the default construction.
    • Operations that define more/fewer phases; do we synthesize the "all projects, all phases" virtual command for the full graph?
    • Interaction with plugins that inject pre/post operation/iteration hooks that vary by command.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      Needs triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions