Skip to content

Commit ea3b319

Browse files
mojazamojazayeriCopilot
authored
[rush-daemon][WS2] Add daemon host bootstrap (#5928)
* [rush-daemon] Add daemon host bootstrap Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * [rush-daemon] Refresh injected dependency metadata Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * [rush-daemon-protocol] Preserve pong compatibility Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * [rush-daemon] Move rushd entrypoint into daemon package Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: mojaza <mojazayeri@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent a2507e8 commit ea3b319

22 files changed

Lines changed: 677 additions & 17 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@rushstack/rush-daemon-protocol",
5+
"comment": "Include daemon and protocol version metadata in pong control messages.",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@rushstack/rush-daemon-protocol",
10+
"email": "mojazayeri@users.noreply.github.com"
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@rushstack/rush-daemon",
5+
"comment": "Add the rushd executable and workspace-keyed daemon host bootstrap with handshake, liveness, readiness, and clean shutdown lifecycle.",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@rushstack/rush-daemon",
10+
"email": "mojazayeri@users.noreply.github.com"
11+
}

common/config/rush/browser-approved-packages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
},
5353
{
5454
"name": "@rushstack/rush-daemon-transport",
55-
"allowedCategories": [ "tests" ]
55+
"allowedCategories": [ "libraries", "tests" ]
5656
},
5757
{
5858
"name": "@rushstack/rush-serve-dashboard",

common/config/subspaces/default/pnpm-lock.yaml

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/reviews/api/rush-daemon-protocol.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,8 @@ export interface IDaemonPongMessage {
292292
readonly kind: 'pong';
293293
// (undocumented)
294294
readonly payload: {
295+
readonly daemonVersion?: string;
296+
readonly protocolVersion?: IDaemonProtocolVersion;
295297
readonly uptimeMs: number;
296298
};
297299
}

common/reviews/api/rush-daemon.api.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
/// <reference types="node" />
88

9+
import type { IDaemonPaths } from '@rushstack/rush-daemon-transport';
10+
911
// @public
1012
export interface IRequestLease {
1113
// (undocumented)
@@ -23,6 +25,21 @@ export interface IRequestSchedulerAcquireOptions {
2325
waitTimeoutMs?: number;
2426
}
2527

28+
// @beta
29+
export interface IRushDaemonHostOptions {
30+
readonly daemonVersion: string;
31+
readonly onError?: (error: Error) => void;
32+
readonly repoRoot: string;
33+
readonly rushVersion: string;
34+
readonly startupOptions?: Readonly<Record<string, unknown>>;
35+
}
36+
37+
// @beta
38+
export interface IRushDaemonServeOptions extends IRushDaemonHostOptions {
39+
readonly onReady?: (host: RushDaemonHost) => void | Promise<void>;
40+
readonly shutdownSignal?: AbortSignal;
41+
}
42+
2643
// @public
2744
export enum RequestExclusivityClass {
2845
// (undocumented)
@@ -57,6 +74,17 @@ export enum RequestSchedulerErrorCode {
5774
WaitTimeout = "WAIT_TIMEOUT"
5875
}
5976

77+
// @beta
78+
export class RushDaemonHost {
79+
closeAsync(): Promise<void>;
80+
// (undocumented)
81+
readonly paths: IDaemonPaths;
82+
static startAsync(options: IRushDaemonHostOptions): Promise<RushDaemonHost>;
83+
}
84+
85+
// @beta
86+
export function serveRushDaemonAsync(options: IRushDaemonServeOptions): Promise<void>;
87+
6088
// (No @packageDocumentation comment for this package)
6189

6290
```

libraries/rush-daemon-protocol/src/ControlMessageValidation.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { isDaemonControlMessageKind } from './DaemonControlMessage';
55
import { DaemonProtocolError } from './DaemonProtocolError';
66
import { isDaemonVerbosity } from './DaemonVerbosity';
77

8-
/** Returns `true` when `value` is a plain object. @beta */
8+
/** Returns `true` when `value` is a non-null object usable as a control record. @beta */
99
export function isDaemonControlRecord(value: unknown): value is Record<string, unknown> {
1010
return typeof value === 'object' && value !== null;
1111
}
@@ -45,6 +45,12 @@ function validateHelloAck(payload: Record<string, unknown>): void {
4545
requireStringField(payload, 'sessionId');
4646
}
4747

48+
function validatePong(payload: Record<string, unknown>): void {
49+
if (payload.daemonVersion !== undefined) requireStringField(payload, 'daemonVersion');
50+
if (payload.protocolVersion !== undefined) requireVersion(payload);
51+
requireNumberField(payload, 'uptimeMs');
52+
}
53+
4854
function validateSubscribe(payload: Record<string, unknown>): void {
4955
if (typeof payload.isTTY !== 'boolean') {
5056
fail('Subscribe message payload.isTTY must be a boolean.');
@@ -73,13 +79,11 @@ const VALIDATORS_BY_KIND: Record<string, ControlValidator> = {
7379
subscribe: validateSubscribe,
7480
unsubscribe: noopValidator,
7581
ping: noopValidator,
76-
pong: (payload: Record<string, unknown>) => requireNumberField(payload, 'uptimeMs'),
82+
pong: validatePong,
7783
error: validateError
7884
};
7985

80-
/**
81-
* Structurally validates a parsed control message.
82-
*
86+
/** Structurally validates a parsed control message.
8387
* @throws {@link DaemonProtocolError} when the value is not a well-formed control message.
8488
*
8589
* @beta

libraries/rush-daemon-protocol/src/DaemonControlMessage.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// See LICENSE in the project root for license information.
33

44
import type { IDaemonClientCaps } from './DaemonClientCaps';
5+
import type { IDaemonPongMessage } from './DaemonPongMessage';
56
import type { DaemonProtocolErrorCode } from './DaemonProtocolError';
67
import type { IDaemonProtocolVersion } from './DaemonProtocolVersion';
78

@@ -41,12 +42,6 @@ export interface IDaemonPingMessage {
4142
readonly payload: DaemonEmptyPayload;
4243
}
4344

44-
/** The liveness reply. @beta */
45-
export interface IDaemonPongMessage {
46-
readonly kind: 'pong';
47-
readonly payload: { readonly uptimeMs: number };
48-
}
49-
5045
/** A protocol error sent on the wire. @beta */
5146
export interface IDaemonErrorMessage {
5247
readonly kind: 'error';
@@ -89,7 +84,7 @@ export const DAEMON_CONTROL_MESSAGE_KINDS: readonly [
8984
'error'
9085
] = ['hello', 'helloAck', 'subscribe', 'unsubscribe', 'ping', 'pong', 'error'];
9186

92-
/** The union of control message `kind` discriminants, derived from the list. @beta */
87+
/** The union of control message `kind` discriminants, derived from the runtime list. @beta */
9388
export type DaemonControlMessageKind = (typeof DAEMON_CONTROL_MESSAGE_KINDS)[number];
9489

9590
const CONTROL_KIND_SET: ReadonlySet<string> = new Set<string>(DAEMON_CONTROL_MESSAGE_KINDS);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import type { IDaemonProtocolVersion } from './DaemonProtocolVersion';
5+
6+
/** The liveness reply. @beta */
7+
export interface IDaemonPongMessage {
8+
readonly kind: 'pong';
9+
readonly payload: {
10+
/** The daemon implementation version, when reported by protocol 0.2 or newer. */
11+
readonly daemonVersion?: string;
12+
/** The daemon wire protocol version, when reported by protocol 0.2 or newer. */
13+
readonly protocolVersion?: IDaemonProtocolVersion;
14+
readonly uptimeMs: number;
15+
};
16+
}

libraries/rush-daemon-protocol/src/DaemonProtocolVersion.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export interface IDaemonProtocolVersion {
3434
*/
3535
export const DAEMON_PROTOCOL_VERSION: IDaemonProtocolVersion = {
3636
major: 0,
37-
minor: 1
37+
minor: 2
3838
};
3939

4040
/**

0 commit comments

Comments
 (0)