@relayflows/sdk 2.0.0
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/dist/authored-flow-error.d.ts +9 -0
- package/dist/authored-flow-error.d.ts.map +1 -0
- package/dist/authored-flow-error.js +13 -0
- package/dist/authored-flow-error.js.map +1 -0
- package/dist/authored-flow-executor.d.ts +28 -0
- package/dist/authored-flow-executor.d.ts.map +1 -0
- package/dist/authored-flow-executor.js +203 -0
- package/dist/authored-flow-executor.js.map +1 -0
- package/dist/authored-flow-lifecycle.d.ts +61 -0
- package/dist/authored-flow-lifecycle.d.ts.map +1 -0
- package/dist/authored-flow-lifecycle.js +284 -0
- package/dist/authored-flow-lifecycle.js.map +1 -0
- package/dist/authored-flow-loader.d.ts +7 -0
- package/dist/authored-flow-loader.d.ts.map +1 -0
- package/dist/authored-flow-loader.js +39 -0
- package/dist/authored-flow-loader.js.map +1 -0
- package/dist/authored-flow-operation.d.ts +43 -0
- package/dist/authored-flow-operation.d.ts.map +1 -0
- package/dist/authored-flow-operation.js +176 -0
- package/dist/authored-flow-operation.js.map +1 -0
- package/dist/authored-flow.d.ts +12 -0
- package/dist/authored-flow.d.ts.map +1 -0
- package/dist/authored-flow.js +13 -0
- package/dist/authored-flow.js.map +1 -0
- package/dist/authored-promise-graph.d.ts +67 -0
- package/dist/authored-promise-graph.d.ts.map +1 -0
- package/dist/authored-promise-graph.js +206 -0
- package/dist/authored-promise-graph.js.map +1 -0
- package/dist/backlog-picker.d.ts +55 -0
- package/dist/backlog-picker.d.ts.map +1 -0
- package/dist/backlog-picker.js +117 -0
- package/dist/backlog-picker.js.map +1 -0
- package/dist/canonical.d.ts +18 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +55 -0
- package/dist/canonical.js.map +1 -0
- package/dist/cli/check.d.ts +30 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +324 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/direct-run.d.ts +3 -0
- package/dist/cli/direct-run.d.ts.map +1 -0
- package/dist/cli/direct-run.js +69 -0
- package/dist/cli/direct-run.js.map +1 -0
- package/dist/cli/hn-monitor.d.ts +107 -0
- package/dist/cli/hn-monitor.d.ts.map +1 -0
- package/dist/cli/hn-monitor.js +220 -0
- package/dist/cli/hn-monitor.js.map +1 -0
- package/dist/cli/interruptible-sleep.d.ts +13 -0
- package/dist/cli/interruptible-sleep.d.ts.map +1 -0
- package/dist/cli/interruptible-sleep.js +31 -0
- package/dist/cli/interruptible-sleep.js.map +1 -0
- package/dist/cli/run.d.ts +54 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +316 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/tick-runner.d.ts +151 -0
- package/dist/cli/tick-runner.d.ts.map +1 -0
- package/dist/cli/tick-runner.js +258 -0
- package/dist/cli/tick-runner.js.map +1 -0
- package/dist/cli-adapter.d.ts +29 -0
- package/dist/cli-adapter.d.ts.map +1 -0
- package/dist/cli-adapter.js +92 -0
- package/dist/cli-adapter.js.map +1 -0
- package/dist/cli-executable.d.ts +3 -0
- package/dist/cli-executable.d.ts.map +1 -0
- package/dist/cli-executable.js +10 -0
- package/dist/cli-executable.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +348 -0
- package/dist/cli.js.map +1 -0
- package/dist/compile.d.ts +42 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +515 -0
- package/dist/compile.js.map +1 -0
- package/dist/demo-hn-monitor.d.ts +2 -0
- package/dist/demo-hn-monitor.d.ts.map +1 -0
- package/dist/demo-hn-monitor.js +118 -0
- package/dist/demo-hn-monitor.js.map +1 -0
- package/dist/dir-watcher-poller.d.ts +73 -0
- package/dist/dir-watcher-poller.d.ts.map +1 -0
- package/dist/dir-watcher-poller.js +80 -0
- package/dist/dir-watcher-poller.js.map +1 -0
- package/dist/direct-input.d.ts +10 -0
- package/dist/direct-input.d.ts.map +1 -0
- package/dist/direct-input.js +61 -0
- package/dist/direct-input.js.map +1 -0
- package/dist/failure-kinds.d.ts +25 -0
- package/dist/failure-kinds.d.ts.map +1 -0
- package/dist/failure-kinds.js +64 -0
- package/dist/failure-kinds.js.map +1 -0
- package/dist/gate-contract.d.ts +24 -0
- package/dist/gate-contract.d.ts.map +1 -0
- package/dist/gate-contract.js +50 -0
- package/dist/gate-contract.js.map +1 -0
- package/dist/hn-poller.d.ts +50 -0
- package/dist/hn-poller.d.ts.map +1 -0
- package/dist/hn-poller.js +79 -0
- package/dist/hn-poller.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/journal-client.d.ts +122 -0
- package/dist/journal-client.d.ts.map +1 -0
- package/dist/journal-client.js +277 -0
- package/dist/journal-client.js.map +1 -0
- package/dist/json-schema-bound.d.ts +7 -0
- package/dist/json-schema-bound.d.ts.map +1 -0
- package/dist/json-schema-bound.js +353 -0
- package/dist/json-schema-bound.js.map +1 -0
- package/dist/json-schema.d.ts +5 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +72 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/json-value.d.ts +6 -0
- package/dist/json-value.d.ts.map +1 -0
- package/dist/json-value.js +94 -0
- package/dist/json-value.js.map +1 -0
- package/dist/model-name.d.ts +7 -0
- package/dist/model-name.d.ts.map +1 -0
- package/dist/model-name.js +21 -0
- package/dist/model-name.js.map +1 -0
- package/dist/output-schema.d.ts +8 -0
- package/dist/output-schema.d.ts.map +1 -0
- package/dist/output-schema.js +28 -0
- package/dist/output-schema.js.map +1 -0
- package/dist/preflight.d.ts +80 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +361 -0
- package/dist/preflight.js.map +1 -0
- package/dist/protocol.d.ts +359 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +15 -0
- package/dist/protocol.js.map +1 -0
- package/dist/spec.d.ts +294 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +13 -0
- package/dist/spec.js.map +1 -0
- package/dist/step-dependencies.d.ts +2 -0
- package/dist/step-dependencies.d.ts.map +1 -0
- package/dist/step-dependencies.js +88 -0
- package/dist/step-dependencies.js.map +1 -0
- package/dist/step-fields.d.ts +17 -0
- package/dist/step-fields.d.ts.map +1 -0
- package/dist/step-fields.js +32 -0
- package/dist/step-fields.js.map +1 -0
- package/dist/tick-source.d.ts +205 -0
- package/dist/tick-source.d.ts.map +1 -0
- package/dist/tick-source.js +234 -0
- package/dist/tick-source.js.map +1 -0
- package/dist/unknown-keys.d.ts +7 -0
- package/dist/unknown-keys.d.ts.map +1 -0
- package/dist/unknown-keys.js +47 -0
- package/dist/unknown-keys.js.map +1 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +458 -0
- package/dist/validate.js.map +1 -0
- package/dist/work-package-consumer.d.ts +33 -0
- package/dist/work-package-consumer.d.ts.map +1 -0
- package/dist/work-package-consumer.js +44 -0
- package/dist/work-package-consumer.js.map +1 -0
- package/dist/work-package-validator.d.ts +15 -0
- package/dist/work-package-validator.d.ts.map +1 -0
- package/dist/work-package-validator.js +72 -0
- package/dist/work-package-validator.js.map +1 -0
- package/dist/worker-cli.d.ts +16 -0
- package/dist/worker-cli.d.ts.map +1 -0
- package/dist/worker-cli.js +77 -0
- package/dist/worker-cli.js.map +1 -0
- package/dist/worker.d.ts +57 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +129 -0
- package/dist/worker.js.map +1 -0
- package/dist/wrapper-runtime.d.ts +10 -0
- package/dist/wrapper-runtime.d.ts.map +1 -0
- package/dist/wrapper-runtime.js +83 -0
- package/dist/wrapper-runtime.js.map +1 -0
- package/dist/wrapper-session.d.ts +16 -0
- package/dist/wrapper-session.d.ts.map +1 -0
- package/dist/wrapper-session.js +244 -0
- package/dist/wrapper-session.js.map +1 -0
- package/package.json +50 -0
- package/src/authored-flow-error.ts +31 -0
- package/src/authored-flow-executor.ts +365 -0
- package/src/authored-flow-lifecycle.ts +344 -0
- package/src/authored-flow-loader.ts +44 -0
- package/src/authored-flow-operation.ts +252 -0
- package/src/authored-flow.ts +21 -0
- package/src/authored-promise-graph.ts +196 -0
- package/src/backlog-picker.ts +153 -0
- package/src/canonical.ts +57 -0
- package/src/cli/check.ts +391 -0
- package/src/cli/direct-run.ts +86 -0
- package/src/cli/hn-monitor.ts +286 -0
- package/src/cli/interruptible-sleep.ts +27 -0
- package/src/cli/run.ts +439 -0
- package/src/cli/tick-runner.ts +378 -0
- package/src/cli-adapter.ts +115 -0
- package/src/cli-executable.ts +12 -0
- package/src/cli.ts +364 -0
- package/src/compile.ts +573 -0
- package/src/demo-hn-monitor.ts +132 -0
- package/src/dir-watcher-poller.ts +122 -0
- package/src/direct-input.ts +69 -0
- package/src/failure-kinds.ts +77 -0
- package/src/gate-contract.ts +72 -0
- package/src/hn-poller.ts +104 -0
- package/src/index.ts +195 -0
- package/src/journal-client.ts +379 -0
- package/src/json-schema-bound.ts +357 -0
- package/src/json-schema.ts +65 -0
- package/src/json-value.ts +110 -0
- package/src/model-name.ts +20 -0
- package/src/output-schema.ts +33 -0
- package/src/preflight.ts +482 -0
- package/src/protocol.ts +364 -0
- package/src/spec.ts +343 -0
- package/src/step-dependencies.ts +100 -0
- package/src/step-fields.ts +36 -0
- package/src/tick-source.ts +334 -0
- package/src/unknown-keys.ts +52 -0
- package/src/validate.ts +503 -0
- package/src/work-package-consumer.ts +73 -0
- package/src/work-package-validator.ts +90 -0
- package/src/worker-cli.ts +110 -0
- package/src/worker.ts +150 -0
- package/src/wrapper-runtime.ts +93 -0
- package/src/wrapper-session.ts +287 -0
package/dist/cli/run.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { join, resolve } from 'node:path';
|
|
2
|
+
import { toKernelSpec } from '../compile.js';
|
|
3
|
+
import { JournalClient, JournalProtocolError } from '../journal-client.js';
|
|
4
|
+
import { checkFlow, } from './check.js';
|
|
5
|
+
export async function runFlow(path, dataDir, options = {}) {
|
|
6
|
+
const checked = checkFlow(path);
|
|
7
|
+
if (!checked.report.ok || checked.flow === undefined) {
|
|
8
|
+
return { exitCode: 2, report: fromCheckReport('run', checked.report) };
|
|
9
|
+
}
|
|
10
|
+
return executeCheckedFlow(checked, dataDir, options);
|
|
11
|
+
}
|
|
12
|
+
async function executeCheckedFlow(checked, dataDir, options) {
|
|
13
|
+
const socketPath = socketFor(dataDir);
|
|
14
|
+
const client = new JournalClient(socketPath);
|
|
15
|
+
const connected = await connect(client, 'run', dataDir, checked.report);
|
|
16
|
+
if (connected !== undefined)
|
|
17
|
+
return connected;
|
|
18
|
+
try {
|
|
19
|
+
const spec = toKernelSpec(checked.flow);
|
|
20
|
+
const outcome = await client.runStart(spec);
|
|
21
|
+
return await classifyOutcome(client, 'run', outcome, checked.report, socketPath, options);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return protocolFailure('run', checked.report, socketPath, error);
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
client.close();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function resumeFlow(runId, dataDir, options = {}) {
|
|
31
|
+
const socketPath = socketFor(dataDir);
|
|
32
|
+
const base = emptyReport('resume');
|
|
33
|
+
const client = new JournalClient(socketPath);
|
|
34
|
+
const connected = await connect(client, 'resume', dataDir, base);
|
|
35
|
+
if (connected !== undefined)
|
|
36
|
+
return connected;
|
|
37
|
+
try {
|
|
38
|
+
const outcome = await client.runResume(runId);
|
|
39
|
+
return await classifyOutcome(client, 'resume', outcome, base, socketPath, options);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (!(error instanceof JournalProtocolError) || error.code !== 'run_not_found') {
|
|
43
|
+
return protocolFailure('resume', base, socketPath, error, runId);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
exitCode: 2,
|
|
47
|
+
report: {
|
|
48
|
+
...base,
|
|
49
|
+
runId,
|
|
50
|
+
socketPath,
|
|
51
|
+
diagnostics: [{
|
|
52
|
+
severity: 'refusal',
|
|
53
|
+
kind: 'run_unavailable',
|
|
54
|
+
message: `Run "${runId}" could not be resumed by relayflowd at "${socketPath}": ${errorMessage(error)}`,
|
|
55
|
+
}],
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
client.close();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export async function connect(client, command, dataDir, base) {
|
|
64
|
+
const socketPath = socketFor(dataDir);
|
|
65
|
+
try {
|
|
66
|
+
await client.connect();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
client.close();
|
|
70
|
+
return {
|
|
71
|
+
exitCode: 2,
|
|
72
|
+
report: {
|
|
73
|
+
...fromBase(command, base),
|
|
74
|
+
socketPath,
|
|
75
|
+
diagnostics: [
|
|
76
|
+
...base.diagnostics,
|
|
77
|
+
{
|
|
78
|
+
severity: 'refusal',
|
|
79
|
+
kind: 'daemon_unreachable',
|
|
80
|
+
message: `No compatible relayflowd is listening at "${socketPath}". Start it with: relayflowd --data-dir ${JSON.stringify(dataDir)} serve`,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
await client.hello(`flows-${command}`);
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
client.close();
|
|
92
|
+
return protocolFailure(command, base, socketPath, error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/// Exported for tests. The `running`-with-no-identifiable-step branch (#179)
|
|
96
|
+
/// only occurs in a sub-second window against a live daemon, so pinning it
|
|
97
|
+
/// needs a stubbed client rather than a real run -- the integration test that
|
|
98
|
+
/// found it reproduced the bug roughly 1 time in 12.
|
|
99
|
+
export async function classifyOutcome(client, command, outcome, base, socketPath, options) {
|
|
100
|
+
let current = outcome;
|
|
101
|
+
let parkedStep;
|
|
102
|
+
let needsHuman = false;
|
|
103
|
+
let unclassifiedPolls = 0;
|
|
104
|
+
while (current.status === 'parked') {
|
|
105
|
+
const inspection = await inspectOutOfBandStep(client, current.run_id);
|
|
106
|
+
if (inspection?.parkedStep !== undefined) {
|
|
107
|
+
parkedStep = inspection.parkedStep;
|
|
108
|
+
needsHuman = inspection.needsHuman;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
if (inspection?.runningStep !== undefined) {
|
|
112
|
+
await waitForRunningStep(client, current.run_id, inspection.runningStep, options);
|
|
113
|
+
current = await client.runResume(current.run_id);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (inspection?.status === 'completed' || inspection?.status === 'failed') {
|
|
117
|
+
current = await client.runResume(current.run_id);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
// The run is still RUNNING but no step is identifiable at this instant.
|
|
121
|
+
//
|
|
122
|
+
// That is a healthy state, not a protocol error. It happens when a worker
|
|
123
|
+
// has just completed the step this run parked on and the daemon has not yet
|
|
124
|
+
// finished driving what follows: nothing is `needs_human`, `runnable` or
|
|
125
|
+
// `running` for a moment, while the snapshot's own status is `running`.
|
|
126
|
+
// Breaking here left `status === 'parked'` with no `parkedStep`, so the
|
|
127
|
+
// tail reported `parked without a classifiable completion` -- a spurious
|
|
128
|
+
// failure on a run that was about to succeed (#179). Reproduced 1 in 4-15
|
|
129
|
+
// locally; the probe that caught it printed
|
|
130
|
+
// `inspection={"status":"running","needsHuman":false}`.
|
|
131
|
+
//
|
|
132
|
+
// So poll it, bounded. Resuming immediately would spin, since the daemon
|
|
133
|
+
// needs a moment to advance.
|
|
134
|
+
if (inspection?.status === 'running' && unclassifiedPolls < MAX_UNCLASSIFIED_POLLS) {
|
|
135
|
+
unclassifiedPolls += 1;
|
|
136
|
+
// `delay(ms, signal)`, not a bare setTimeout: every other wait in this
|
|
137
|
+
// file is cancel-aware, and an uncancellable one here would keep polling
|
|
138
|
+
// the daemon for up to 2s after a Ctrl-C or a lifecycle abort.
|
|
139
|
+
throwIfCanceled(options.signal, current.run_id);
|
|
140
|
+
await delay(UNCLASSIFIED_POLL_MS, options.signal);
|
|
141
|
+
// Redundant resumes are safe: `run.resume` is idempotent on a run that
|
|
142
|
+
// is already progressing -- it returns the current state rather than
|
|
143
|
+
// re-dispatching. This loop leans on that up to MAX_UNCLASSIFIED_POLLS
|
|
144
|
+
// times while the daemon is mid-transition.
|
|
145
|
+
current = await client.runResume(current.run_id);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// Fail closed rather than loop forever: if it never resolves, the original
|
|
149
|
+
// error below still fires and says so.
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
const report = {
|
|
153
|
+
...fromBase(command, base),
|
|
154
|
+
ok: current.status === 'completed' && current.completion_reason === 'success',
|
|
155
|
+
runId: current.run_id,
|
|
156
|
+
socketPath,
|
|
157
|
+
status: current.status,
|
|
158
|
+
...(current.completion_reason !== null ? { completionReason: current.completion_reason } : {}),
|
|
159
|
+
completedSteps: current.completed_steps,
|
|
160
|
+
};
|
|
161
|
+
if (report.ok)
|
|
162
|
+
return { exitCode: 0, report };
|
|
163
|
+
if (current.status === 'failed' && current.completion_reason !== null) {
|
|
164
|
+
return {
|
|
165
|
+
exitCode: 1,
|
|
166
|
+
report: {
|
|
167
|
+
...report,
|
|
168
|
+
diagnostics: [...report.diagnostics, {
|
|
169
|
+
severity: 'failure',
|
|
170
|
+
kind: current.completion_reason,
|
|
171
|
+
message: `Run "${current.run_id}" failed with completionReason: ${current.completion_reason}.`,
|
|
172
|
+
}],
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (current.status === 'parked' && parkedStep !== undefined) {
|
|
177
|
+
return {
|
|
178
|
+
exitCode: 3,
|
|
179
|
+
report: {
|
|
180
|
+
...report,
|
|
181
|
+
parkedStep,
|
|
182
|
+
diagnostics: [...report.diagnostics, {
|
|
183
|
+
severity: 'parked',
|
|
184
|
+
kind: 'run_parked',
|
|
185
|
+
message: needsHuman
|
|
186
|
+
? `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): waiting for human recovery after the worker attempt failed.`
|
|
187
|
+
: `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): no worker is attached for step type "${parkedStep.type}".`,
|
|
188
|
+
}],
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return protocolFailure(command, base, socketPath, new Error(`relayflowd returned status ${current.status} without a classifiable completion`), current.run_id);
|
|
193
|
+
}
|
|
194
|
+
// Bound on re-polling a run that reports `running` with no identifiable step.
|
|
195
|
+
// 40 x 50ms = 2s, far longer than the sub-second window observed in #179, and
|
|
196
|
+
// short enough that a genuinely stuck run still reports rather than hangs.
|
|
197
|
+
const MAX_UNCLASSIFIED_POLLS = 40;
|
|
198
|
+
const UNCLASSIFIED_POLL_MS = 50;
|
|
199
|
+
async function inspectOutOfBandStep(client, runId) {
|
|
200
|
+
const snapshot = await client.runGet(runId);
|
|
201
|
+
const entries = Object.entries(snapshot.steps);
|
|
202
|
+
const humanEntry = entries.find(([, step]) => step.type !== 'deterministic' && step.state === 'needs_human');
|
|
203
|
+
const runnableEntry = entries.find(([, step]) => step.type !== 'deterministic' && step.state === 'runnable');
|
|
204
|
+
const runningEntry = entries.find(([, step]) => step.type !== 'deterministic' && step.state === 'running');
|
|
205
|
+
const parkedEntry = humanEntry ?? runnableEntry;
|
|
206
|
+
const parkedStep = parkedEntry === undefined ? undefined : {
|
|
207
|
+
id: parkedEntry[0],
|
|
208
|
+
type: parkedEntry[1].type,
|
|
209
|
+
};
|
|
210
|
+
const runningStep = runningEntry === undefined ? undefined : {
|
|
211
|
+
id: runningEntry[0],
|
|
212
|
+
type: runningEntry[1].type,
|
|
213
|
+
leaseDeadlineMs: runningEntry[1].lease_deadline_ms ?? Number.NaN,
|
|
214
|
+
};
|
|
215
|
+
return {
|
|
216
|
+
status: snapshot.status,
|
|
217
|
+
needsHuman: humanEntry !== undefined,
|
|
218
|
+
...(parkedStep !== undefined ? { parkedStep } : {}),
|
|
219
|
+
...(runningStep !== undefined ? { runningStep } : {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
async function waitForRunningStep(client, runId, runningStep, options) {
|
|
223
|
+
let leaseDeadlineMs = runningStep.leaseDeadlineMs;
|
|
224
|
+
if (!Number.isFinite(leaseDeadlineMs)) {
|
|
225
|
+
throw new Error(`running step "${runningStep.id}" omitted lease_deadline_ms`);
|
|
226
|
+
}
|
|
227
|
+
options.onWait?.({
|
|
228
|
+
runId,
|
|
229
|
+
stepId: runningStep.id,
|
|
230
|
+
stepType: runningStep.type,
|
|
231
|
+
leaseDeadlineMs,
|
|
232
|
+
});
|
|
233
|
+
while (true) {
|
|
234
|
+
throwIfCanceled(options.signal, runningStep.id);
|
|
235
|
+
const remainingMs = leaseDeadlineMs - Date.now();
|
|
236
|
+
if (remainingMs <= 0) {
|
|
237
|
+
throw new Error(`worker lease for step "${runningStep.id}" expired at ${leaseDeadlineMs} without completion`);
|
|
238
|
+
}
|
|
239
|
+
await delay(Math.min(50, remainingMs), options.signal);
|
|
240
|
+
const snapshot = await client.runGet(runId);
|
|
241
|
+
const step = snapshot.steps[runningStep.id];
|
|
242
|
+
if (step?.state !== 'running')
|
|
243
|
+
return;
|
|
244
|
+
if (step.lease_deadline_ms !== undefined && step.lease_deadline_ms !== leaseDeadlineMs) {
|
|
245
|
+
leaseDeadlineMs = step.lease_deadline_ms;
|
|
246
|
+
options.onWait?.({
|
|
247
|
+
runId,
|
|
248
|
+
stepId: runningStep.id,
|
|
249
|
+
stepType: runningStep.type,
|
|
250
|
+
leaseDeadlineMs,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
export function protocolFailure(command, base, socketPath, error, runId) {
|
|
256
|
+
return {
|
|
257
|
+
exitCode: 1,
|
|
258
|
+
report: {
|
|
259
|
+
...fromBase(command, base),
|
|
260
|
+
...(runId !== undefined ? { runId } : {}),
|
|
261
|
+
socketPath,
|
|
262
|
+
diagnostics: [...base.diagnostics, {
|
|
263
|
+
severity: 'failure',
|
|
264
|
+
kind: 'protocol_error',
|
|
265
|
+
message: `relayflowd could not complete the ${command} request: ${errorMessage(error)}`,
|
|
266
|
+
}],
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
export function fromCheckReport(command, report) {
|
|
271
|
+
return {
|
|
272
|
+
ok: false,
|
|
273
|
+
command,
|
|
274
|
+
...(report.path !== undefined ? { path: report.path } : {}),
|
|
275
|
+
...(report.projectConfigPath !== undefined ? { projectConfigPath: report.projectConfigPath } : {}),
|
|
276
|
+
resolutions: report.resolutions,
|
|
277
|
+
diagnostics: report.diagnostics,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
export function emptyReport(command) {
|
|
281
|
+
return { ok: false, command, resolutions: [], diagnostics: [] };
|
|
282
|
+
}
|
|
283
|
+
function fromBase(command, base) {
|
|
284
|
+
return 'command' in base ? base : fromCheckReport(command, base);
|
|
285
|
+
}
|
|
286
|
+
export function socketFor(dataDir) {
|
|
287
|
+
return join(resolve(dataDir), 'relayflowd.sock');
|
|
288
|
+
}
|
|
289
|
+
function errorMessage(error) {
|
|
290
|
+
return error instanceof Error ? error.message : 'unknown protocol error';
|
|
291
|
+
}
|
|
292
|
+
function throwIfCanceled(signal, stepId) {
|
|
293
|
+
if (signal?.aborted === true)
|
|
294
|
+
throw new Error(`waiting for running step "${stepId}" was canceled`);
|
|
295
|
+
}
|
|
296
|
+
function delay(ms, signal) {
|
|
297
|
+
return new Promise((resolveDelay, rejectDelay) => {
|
|
298
|
+
const finish = () => {
|
|
299
|
+
signal?.removeEventListener('abort', cancel);
|
|
300
|
+
resolveDelay();
|
|
301
|
+
};
|
|
302
|
+
const timer = setTimeout(finish, ms);
|
|
303
|
+
if (signal === undefined)
|
|
304
|
+
return;
|
|
305
|
+
const cancel = () => {
|
|
306
|
+
clearTimeout(timer);
|
|
307
|
+
signal.removeEventListener('abort', cancel);
|
|
308
|
+
rejectDelay(new Error('worker wait canceled'));
|
|
309
|
+
};
|
|
310
|
+
if (signal.aborted)
|
|
311
|
+
cancel();
|
|
312
|
+
else
|
|
313
|
+
signal.addEventListener('abort', cancel, { once: true });
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `flows tick start` — drive a scheduled relayflow.
|
|
3
|
+
*
|
|
4
|
+
* A sibling of `hn-monitor.ts`, not a new species: a public function that
|
|
5
|
+
* composes the primitives directly — connect journal → hello → loop
|
|
6
|
+
* `emitDueTicks` → drain on abort → close. The differences from hn-monitor are
|
|
7
|
+
* only the ones the grid forces.
|
|
8
|
+
*
|
|
9
|
+
* ## Why the cursor is persisted, and why that is the whole point
|
|
10
|
+
*
|
|
11
|
+
* `emitDueTicks` starts a FRESH cursor at the current slot:
|
|
12
|
+
*
|
|
13
|
+
* const firstDue = cursor.lastEmittedSlot === undefined
|
|
14
|
+
* ? currentSlot
|
|
15
|
+
* : cursor.lastEmittedSlot + 1;
|
|
16
|
+
*
|
|
17
|
+
* That is right for a schedule's first ever poll — a new hourly schedule must
|
|
18
|
+
* not backfill from the epoch. But it means an in-memory-only cursor makes a
|
|
19
|
+
* restart SKIP every slot between shutdown and restart, silently. The dedupe
|
|
20
|
+
* key `(schedule_id, scheduled_for_ms)` makes re-delivery of a slot harmless,
|
|
21
|
+
* so a lost cursor cannot double-fire; nothing in the primitive protects
|
|
22
|
+
* against the skip. The runner is where that is either handled or lost, so it
|
|
23
|
+
* persists the cursor and reloads it on start.
|
|
24
|
+
*
|
|
25
|
+
* The distinction the file keeps: "no cursor on disk" means first run, start
|
|
26
|
+
* at the current slot. "A cursor on disk behind the grid" means catch up, and
|
|
27
|
+
* report anything past `maxCatchUp` as skipped. Conflating the two either
|
|
28
|
+
* backfills a new schedule from 1970 or silently drops a restart's arrears.
|
|
29
|
+
*
|
|
30
|
+
* ## Why a skip must reach the operator
|
|
31
|
+
*
|
|
32
|
+
* `skippedSlots` and `TickEmitError` exist because a skip that is only a
|
|
33
|
+
* return value is a skip that a `throw` can discard. `emitDueTicks` guarantees
|
|
34
|
+
* the accounting survives its own failure; this runner is the consumer that
|
|
35
|
+
* makes it visible. A skipped slot is real scheduled work that did not run.
|
|
36
|
+
*/
|
|
37
|
+
import { type TickSchedule } from '../tick-source.js';
|
|
38
|
+
import type { EventSubmitResult, HelloResult } from '../protocol.js';
|
|
39
|
+
import type { CliIo } from '../cli.js';
|
|
40
|
+
/**
|
|
41
|
+
* Minimum client surface the runner uses. Concrete protocol return types
|
|
42
|
+
* rather than `unknown`, so a rename in the journal protocol fails to compile
|
|
43
|
+
* here instead of drifting silently past the interface — the same reason
|
|
44
|
+
* `HnMonitorClient` is shaped this way.
|
|
45
|
+
*/
|
|
46
|
+
export interface TickRunnerClient {
|
|
47
|
+
hello(client: string): Promise<HelloResult>;
|
|
48
|
+
eventSubmit(spec: unknown, event: {
|
|
49
|
+
type: string;
|
|
50
|
+
payload?: unknown;
|
|
51
|
+
key?: string;
|
|
52
|
+
}): Promise<EventSubmitResult>;
|
|
53
|
+
close(): void;
|
|
54
|
+
}
|
|
55
|
+
/** Where the runner's durable cursor lives, and what it holds. */
|
|
56
|
+
export interface TickRunnerState {
|
|
57
|
+
scheduleId: string;
|
|
58
|
+
/** Mirror of `TickCursor.lastEmittedSlot`. Absent before the first emit. */
|
|
59
|
+
lastEmittedSlot?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Wall clock of the last successful submit. Not used for scheduling — the
|
|
62
|
+
* grid owns that — but it is what makes a dead runner detectable, so
|
|
63
|
+
* `staleAfterMs` means something end to end rather than only inside the
|
|
64
|
+
* kernel's own sweep.
|
|
65
|
+
*/
|
|
66
|
+
lastEmittedAtMs?: number;
|
|
67
|
+
/** Every slot ever passed over, oldest first. Append-only. */
|
|
68
|
+
skippedSlots: number[];
|
|
69
|
+
}
|
|
70
|
+
interface TickRunnerArgsBase {
|
|
71
|
+
/** Data directory containing `relayflowd.sock`. Required. */
|
|
72
|
+
dataDir: string;
|
|
73
|
+
/** Absolute path to the canonical flow spec JSON. Required. */
|
|
74
|
+
specPath: string;
|
|
75
|
+
/** The grid. Validated at declaration, before anything connects. */
|
|
76
|
+
schedule: TickSchedule;
|
|
77
|
+
/** How often to look for due slots. Default 15000ms. */
|
|
78
|
+
pollIntervalMs?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Where to persist the cursor. Defaults to
|
|
81
|
+
* `<dataDir>/tick-state/<scheduleId>.json`.
|
|
82
|
+
*/
|
|
83
|
+
statePath?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Cap on poll iterations. Undefined = unbounded (production). 0 means
|
|
86
|
+
* "connect, poll zero times, drain, exit 0" — used by tests that only need
|
|
87
|
+
* the setup and teardown paths.
|
|
88
|
+
*/
|
|
89
|
+
maxPolls?: number;
|
|
90
|
+
/** AbortSignal for external cancellation (tests, SIGINT wiring). */
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
/** Injectable clock so tests can place `now` on the grid deliberately. */
|
|
93
|
+
now?: () => number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Test injection surface. `connectClient` is supplied alone here — unlike
|
|
97
|
+
* hn-monitor, this runner attaches no worker, so there is no pairing to
|
|
98
|
+
* enforce: a tick is submitted through `event.submit` and the kernel dispatches
|
|
99
|
+
* to whatever worker the flow's trigger names.
|
|
100
|
+
*/
|
|
101
|
+
export interface TickRunnerArgs extends TickRunnerArgsBase {
|
|
102
|
+
/**
|
|
103
|
+
* Async, because a real `JournalClient` needs `connect()` before `hello()`.
|
|
104
|
+
* A synchronous injection surface hid that: the unit tests' fake client has
|
|
105
|
+
* no transport, so it connected vacuously and the missing `connect()` only
|
|
106
|
+
* surfaced against a live daemon with `journal client: not connected
|
|
107
|
+
* (hello)`. The default path below owns connect+hello so no caller can
|
|
108
|
+
* forget half of it.
|
|
109
|
+
*/
|
|
110
|
+
connectClient?: (socketPath: string) => Promise<TickRunnerClient>;
|
|
111
|
+
}
|
|
112
|
+
/** Absolute path to the state file for one schedule. */
|
|
113
|
+
export declare function tickStatePath(dataDir: string, scheduleId: string): string;
|
|
114
|
+
/**
|
|
115
|
+
* Load the durable cursor, distinguishing "no state" from "state behind the
|
|
116
|
+
* grid". A missing file is a first run and must start at the current slot; a
|
|
117
|
+
* present file must be honoured however far behind it is, so the arrears are
|
|
118
|
+
* either caught up or reported.
|
|
119
|
+
*
|
|
120
|
+
* A malformed or foreign-schedule state file is a hard error rather than a
|
|
121
|
+
* silent reset: resetting would convert an operator's corrupted file into a
|
|
122
|
+
* silent skip of everything since the last good emit, which is the failure
|
|
123
|
+
* this runner exists to prevent.
|
|
124
|
+
*/
|
|
125
|
+
export declare function loadTickState(path: string, scheduleId: string): Promise<TickRunnerState>;
|
|
126
|
+
/**
|
|
127
|
+
* Persist the cursor. Written to a temp file and renamed, so a crash mid-write
|
|
128
|
+
* leaves the previous good state rather than a truncated file — a truncated
|
|
129
|
+
* file would be a hard error on next start, which is safe but needlessly
|
|
130
|
+
* blocks a runner that had a perfectly good cursor a moment earlier.
|
|
131
|
+
*/
|
|
132
|
+
export declare function saveTickState(path: string, state: TickRunnerState): Promise<void>;
|
|
133
|
+
/** One poll's accounting, for logging and for tests to assert on. */
|
|
134
|
+
export interface TickPollReport {
|
|
135
|
+
emittedSlots: number[];
|
|
136
|
+
skippedSlots: number[];
|
|
137
|
+
/** Set when the poll threw. The partial accounting is still present. */
|
|
138
|
+
failure?: unknown;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Run `flows tick start`. Returns 0 on clean shutdown, 1 on a fatal error.
|
|
142
|
+
*
|
|
143
|
+
* Fatal means: the schedule is invalid, the state file is unreadable or
|
|
144
|
+
* belongs to another schedule, the journal cannot be reached, or a submit
|
|
145
|
+
* failed. A submit failure is fatal by design — `emitDueTicks` leaves the slot
|
|
146
|
+
* due, so retrying is the next poll's job, but a runner that swallows journal
|
|
147
|
+
* failures and keeps looping is the silent-zero this is meant to prevent.
|
|
148
|
+
*/
|
|
149
|
+
export declare function runTickRunner(args: TickRunnerArgs, io: CliIo): Promise<number>;
|
|
150
|
+
export {};
|
|
151
|
+
//# sourceMappingURL=tick-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tick-runner.d.ts","sourceRoot":"","sources":["../../src/cli/tick-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,EASL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAMvC;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5C,WAAW,CACT,IAAI,EAAE,OAAO,EACb,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,UAAU,kBAAkB;IAC1B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,QAAQ,EAAE,YAAY,CAAC;IACvB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACnE;AAUD,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CA6C1B;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvF;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA4GpF"}
|