@almyty/runner 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -13
- package/dist/cli-args.d.ts +2 -0
- package/dist/cli-args.js +6 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +10 -5
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.js +23 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +4 -1
- package/dist/daemon.js +42 -6
- package/dist/daemon.js.map +1 -1
- package/dist/handlers.d.ts +12 -0
- package/dist/handlers.js +67 -7
- package/dist/handlers.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/policy.d.ts +17 -2
- package/dist/policy.js +21 -2
- package/dist/policy.js.map +1 -1
- package/dist/process-manager.d.ts +11 -2
- package/dist/process-manager.js +12 -2
- package/dist/process-manager.js.map +1 -1
- package/dist/protocol.d.ts +58 -0
- package/dist/protocol.js +29 -0
- package/dist/protocol.js.map +1 -1
- package/dist/streamable-client.d.ts +24 -1
- package/dist/streamable-client.js +84 -14
- package/dist/streamable-client.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.js.map +1 -1
- package/dist/workspace-reclaimer.d.ts +72 -0
- package/dist/workspace-reclaimer.js +100 -0
- package/dist/workspace-reclaimer.js.map +1 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"streamable-client.js","sourceRoot":"","sources":["../src/streamable-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,EACL,uBAAuB,EAEvB,gBAAgB,GACjB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"streamable-client.js","sourceRoot":"","sources":["../src/streamable-client.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -41,6 +41,12 @@ export interface ResolvedConfig {
|
|
|
41
41
|
config: RunnerConfig;
|
|
42
42
|
binaryProbeList: string[];
|
|
43
43
|
backendUrl: string;
|
|
44
|
+
/**
|
|
45
|
+
* The organization to register in, sent as X-Organization-Id. Needed
|
|
46
|
+
* when the logged-in user belongs to more than one organization; the
|
|
47
|
+
* backend refuses an organization the user is not a member of.
|
|
48
|
+
*/
|
|
49
|
+
organizationId?: string;
|
|
44
50
|
}
|
|
45
51
|
export interface RunnerInfo {
|
|
46
52
|
name: string;
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAsHA,uEAAuE;AAEvE,MAAM,OAAO,WAAY,SAAQ,KAAK;IACS;IAA8B;IAA3E,YAAY,OAAe,EAAkB,IAAY,EAAkB,IAAc;QACvF,KAAK,CAAC,OAAO,CAAC,CAAC;QAD4B,SAAI,GAAJ,IAAI,CAAQ;QAAkB,SAAI,GAAJ,IAAI,CAAU;QAEvF,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,iBAAiB,EAAE,mBAAmB;IACtC,uBAAuB,EAAE,yBAAyB;IAClD,iBAAiB,EAAE,mBAAmB;IACtC,WAAW,EAAE,aAAa;IAC1B,cAAc,EAAE,gBAAgB;IAChC,sBAAsB,EAAE,wBAAwB;IAChD,OAAO,EAAE,SAAS;CACV,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ProcessManager } from './process-manager.js';
|
|
2
|
+
import { WorkerEnvelope } from './protocol.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reclaims processes for workspaces the backend no longer considers
|
|
5
|
+
* active.
|
|
6
|
+
*
|
|
7
|
+
* Shape: heartbeat reconciliation, not a release RPC. The runner
|
|
8
|
+
* heartbeats every 30s; the backend answers each heartbeat with the set
|
|
9
|
+
* of workspaces it still lists as ACTIVE for this runner; anything this
|
|
10
|
+
* machine is hosting outside that set is killed. A `workspace.release`
|
|
11
|
+
* message would be a single point of failure — drop it once and the
|
|
12
|
+
* user's processes run forever — whereas a set that is re-sent every
|
|
13
|
+
* beat self-heals: a missed reconciliation is corrected 30s later.
|
|
14
|
+
*
|
|
15
|
+
* Two safety rules, because these are processes on the user's own
|
|
16
|
+
* machine:
|
|
17
|
+
*
|
|
18
|
+
* 1. Ambiguity reclaims nothing. An ack with no workspace set, an
|
|
19
|
+
* unparseable set, or an ack that does not correlate to a
|
|
20
|
+
* heartbeat this runner actually sent, all kill nothing and log.
|
|
21
|
+
* The only thing that kills is an explicit, well-formed answer.
|
|
22
|
+
*
|
|
23
|
+
* 2. Nothing newer than the question gets killed. The backend built
|
|
24
|
+
* its answer at the moment it received the heartbeat; a workspace
|
|
25
|
+
* that started on this machine after that could not have been in
|
|
26
|
+
* it. Reclaiming is therefore limited to workspaces whose oldest
|
|
27
|
+
* running process predates the heartbeat we are being answered.
|
|
28
|
+
* Without this, a workspace created in the window between sending
|
|
29
|
+
* a heartbeat and receiving its ack is killed the instant it
|
|
30
|
+
* starts work.
|
|
31
|
+
*/
|
|
32
|
+
/** Minimal surface this needs from the process manager. */
|
|
33
|
+
export type ReclaimableProcesses = Pick<ProcessManager, 'list' | 'killWorkspace'>;
|
|
34
|
+
export interface ReclaimerLog {
|
|
35
|
+
/** User-visible: something on their machine was terminated. */
|
|
36
|
+
info(line: string): void;
|
|
37
|
+
/** Diagnostics: why nothing was terminated. */
|
|
38
|
+
warn(line: string): void;
|
|
39
|
+
}
|
|
40
|
+
export declare class WorkspaceReclaimer {
|
|
41
|
+
private readonly processes;
|
|
42
|
+
private readonly log;
|
|
43
|
+
/** Envelope id -> local ms timestamp at which we sent that heartbeat. */
|
|
44
|
+
private readonly sent;
|
|
45
|
+
constructor(processes: ReclaimableProcesses, log: ReclaimerLog);
|
|
46
|
+
/**
|
|
47
|
+
* Record a heartbeat we just put on the wire, so its ack can be
|
|
48
|
+
* correlated. An ack whose id is not here is ignored: it is either a
|
|
49
|
+
* replayed frame (the stream replays on reconnect via Last-Event-ID)
|
|
50
|
+
* or something we did not ask for, and neither is a reason to kill
|
|
51
|
+
* anything.
|
|
52
|
+
*/
|
|
53
|
+
noteSent(envelopeId: string, sentAt: number): void;
|
|
54
|
+
/**
|
|
55
|
+
* Handle an inbound `heartbeat` envelope from the backend. Returns the
|
|
56
|
+
* workspace ids actually reclaimed (empty when nothing was, for any
|
|
57
|
+
* reason).
|
|
58
|
+
*/
|
|
59
|
+
onAck(env: WorkerEnvelope): Promise<string[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Workspaces with at least one RUNNING process, keyed by id, with the
|
|
62
|
+
* start time of the oldest of them.
|
|
63
|
+
*
|
|
64
|
+
* Only running processes count. Exited ones linger in the manager's
|
|
65
|
+
* retention window so callers can still collect exit info, and
|
|
66
|
+
* treating those as something to reclaim would log a kill that killed
|
|
67
|
+
* nothing. It also makes the whole thing idempotent for free:
|
|
68
|
+
* killWorkspace forgets the processes it killed, so the next
|
|
69
|
+
* heartbeat finds the workspace unhosted and says nothing.
|
|
70
|
+
*/
|
|
71
|
+
private hostedWorkspaces;
|
|
72
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { parseHeartbeatAck } from './protocol.js';
|
|
2
|
+
/**
|
|
3
|
+
* How many un-acked heartbeats to remember. The daemon beats every 30s
|
|
4
|
+
* and an ack rides the same stream, so anything older than a handful of
|
|
5
|
+
* beats is never going to be answered.
|
|
6
|
+
*/
|
|
7
|
+
const MAX_TRACKED_HEARTBEATS = 8;
|
|
8
|
+
export class WorkspaceReclaimer {
|
|
9
|
+
processes;
|
|
10
|
+
log;
|
|
11
|
+
/** Envelope id -> local ms timestamp at which we sent that heartbeat. */
|
|
12
|
+
sent = new Map();
|
|
13
|
+
constructor(processes, log) {
|
|
14
|
+
this.processes = processes;
|
|
15
|
+
this.log = log;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Record a heartbeat we just put on the wire, so its ack can be
|
|
19
|
+
* correlated. An ack whose id is not here is ignored: it is either a
|
|
20
|
+
* replayed frame (the stream replays on reconnect via Last-Event-ID)
|
|
21
|
+
* or something we did not ask for, and neither is a reason to kill
|
|
22
|
+
* anything.
|
|
23
|
+
*/
|
|
24
|
+
noteSent(envelopeId, sentAt) {
|
|
25
|
+
this.sent.set(envelopeId, sentAt);
|
|
26
|
+
while (this.sent.size > MAX_TRACKED_HEARTBEATS) {
|
|
27
|
+
const oldest = this.sent.keys().next().value;
|
|
28
|
+
if (oldest === undefined)
|
|
29
|
+
break;
|
|
30
|
+
this.sent.delete(oldest);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Handle an inbound `heartbeat` envelope from the backend. Returns the
|
|
35
|
+
* workspace ids actually reclaimed (empty when nothing was, for any
|
|
36
|
+
* reason).
|
|
37
|
+
*/
|
|
38
|
+
async onAck(env) {
|
|
39
|
+
if (env.type !== 'heartbeat')
|
|
40
|
+
return [];
|
|
41
|
+
const sentAt = this.sent.get(env.id);
|
|
42
|
+
if (sentAt === undefined) {
|
|
43
|
+
// Consumed already, or never ours. Replayed acks land here, which
|
|
44
|
+
// is what we want: an ack is answered once.
|
|
45
|
+
this.log.warn(`heartbeat ack ${env.id} does not match an outstanding heartbeat; reclaiming nothing`);
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
this.sent.delete(env.id);
|
|
49
|
+
const parsed = parseHeartbeatAck(env.payload);
|
|
50
|
+
if (!parsed.ok) {
|
|
51
|
+
this.log.warn(parsed.reason === 'absent'
|
|
52
|
+
? 'heartbeat ack carried no workspace set; reclaiming nothing ' +
|
|
53
|
+
'(backend predates workspace reconciliation, or could not build the set)'
|
|
54
|
+
: 'heartbeat ack carried an unreadable workspace set; reclaiming nothing');
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const active = new Set(parsed.activeWorkspaceIds);
|
|
58
|
+
const reclaimed = [];
|
|
59
|
+
for (const [workspaceId, hosted] of this.hostedWorkspaces()) {
|
|
60
|
+
if (active.has(workspaceId))
|
|
61
|
+
continue;
|
|
62
|
+
if (hosted.oldestStartedAt > sentAt) {
|
|
63
|
+
// Started after the backend answered; it could not have been in
|
|
64
|
+
// the set. The next heartbeat will see it listed, or reclaim it.
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const killed = await this.processes.killWorkspace(workspaceId);
|
|
68
|
+
reclaimed.push(workspaceId);
|
|
69
|
+
this.log.info(`workspace ${workspaceId} reclaimed: killed ${killed} process(es) ` +
|
|
70
|
+
'because the backend no longer lists it as active');
|
|
71
|
+
}
|
|
72
|
+
return reclaimed;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Workspaces with at least one RUNNING process, keyed by id, with the
|
|
76
|
+
* start time of the oldest of them.
|
|
77
|
+
*
|
|
78
|
+
* Only running processes count. Exited ones linger in the manager's
|
|
79
|
+
* retention window so callers can still collect exit info, and
|
|
80
|
+
* treating those as something to reclaim would log a kill that killed
|
|
81
|
+
* nothing. It also makes the whole thing idempotent for free:
|
|
82
|
+
* killWorkspace forgets the processes it killed, so the next
|
|
83
|
+
* heartbeat finds the workspace unhosted and says nothing.
|
|
84
|
+
*/
|
|
85
|
+
hostedWorkspaces() {
|
|
86
|
+
const hosted = new Map();
|
|
87
|
+
for (const handle of this.processes.list()) {
|
|
88
|
+
if (handle.status !== 'running')
|
|
89
|
+
continue;
|
|
90
|
+
const startedAt = handle.startedAt.getTime();
|
|
91
|
+
const existing = hosted.get(handle.workspaceId);
|
|
92
|
+
if (!existing)
|
|
93
|
+
hosted.set(handle.workspaceId, { oldestStartedAt: startedAt });
|
|
94
|
+
else if (startedAt < existing.oldestStartedAt)
|
|
95
|
+
existing.oldestStartedAt = startedAt;
|
|
96
|
+
}
|
|
97
|
+
return hosted;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=workspace-reclaimer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-reclaimer.js","sourceRoot":"","sources":["../src/workspace-reclaimer.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,iBAAiB,EAAkB,MAAM,eAAe,CAAC;AA0CrF;;;;GAIG;AACH,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC,MAAM,OAAO,kBAAkB;IAKV;IACA;IALnB,yEAAyE;IACxD,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAElD,YACmB,SAA+B,EAC/B,GAAiB;QADjB,cAAS,GAAT,SAAS,CAAsB;QAC/B,QAAG,GAAH,GAAG,CAAc;IACjC,CAAC;IAEJ;;;;;;OAMG;IACH,QAAQ,CAAC,UAAkB,EAAE,MAAc;QACzC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,sBAAsB,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAA2B,CAAC;YACnE,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,GAAmB;QAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,EAAE,CAAC;QAExC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,kEAAkE;YAClE,4CAA4C;YAC5C,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,iBAAiB,GAAG,CAAC,EAAE,8DAA8D,CACtF,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEzB,MAAM,MAAM,GAAsB,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,MAAM,CAAC,MAAM,KAAK,QAAQ;gBACxB,CAAC,CAAC,6DAA6D;oBAC3D,yEAAyE;gBAC7E,CAAC,CAAC,uEAAuE,CAC5E,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;QAClD,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,KAAK,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;YAC5D,IAAI,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC;gBAAE,SAAS;YACtC,IAAI,MAAM,CAAC,eAAe,GAAG,MAAM,EAAE,CAAC;gBACpC,gEAAgE;gBAChE,iEAAiE;gBACjE,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;YAC/D,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,CACX,aAAa,WAAW,sBAAsB,MAAM,eAAe;gBACjE,kDAAkD,CACrD,CAAC;QACJ,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;;;;;;;OAUG;IACK,gBAAgB;QACtB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuC,CAAC;QAC9D,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;gBAAE,SAAS;YAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAChD,IAAI,CAAC,QAAQ;gBAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC,CAAC;iBACzE,IAAI,SAAS,GAAG,QAAQ,CAAC,eAAe;gBAAE,QAAQ,CAAC,eAAe,GAAG,SAAS,CAAC;QACtF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almyty/runner",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"node": ">=20"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
27
|
+
"@almyty/client": "^1.5.1",
|
|
28
|
+
"node-pty": "^1.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^25.4.0",
|