deepline 0.3.127 → 0.3.129
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/bundling-sources/sdk/src/client.ts +34 -9
- package/dist/bundling-sources/sdk/src/http.ts +22 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +22 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +265 -2
- package/dist/bundling-sources/shared_libs/play-runtime/bounded-batch-function.ts +682 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +21 -5
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5390 -1732
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +107 -1
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +229 -7
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +25 -4
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-capacity.ts +71 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +694 -28
- package/dist/bundling-sources/shared_libs/play-runtime/egress-bandwidth-probe.ts +167 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-receipt-output-reference.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-response-size.ts +27 -0
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +66 -1
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +425 -71
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +210 -32
- package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +27 -13
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +19 -6
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +61 -2
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +33 -1
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +42 -1
- package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +11 -11
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +49 -16
- package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +1653 -98
- package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +807 -0
- package/dist/bundling-sources/shared_libs/play-runtime/memory-pressure-signal.ts +138 -0
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +85 -3
- package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +60 -2
- package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +46 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +70 -27
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +56 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/adaptive-provider-capacity-controller.ts +192 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/epoch-aimd-rate-controller.ts +194 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/fixture-capacity-simulator.ts +220 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/gradient2-concurrency-controller.ts +214 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-capacity-policy.ts +43 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-concurrency-policy.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-rate-policy.ts +95 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-throttle-classifier.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +1535 -11
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +49 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +55 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +221 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +339 -29
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +28 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +192 -165
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +90 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +281 -6
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +27 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +19 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +108 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +11 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-compression.ts +276 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +723 -115
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +98 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +3 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +41 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +448 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-map-row-feed.ts +215 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +11 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +161 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-value.ts +184 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +607 -121
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +15 -2
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +71 -14
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +288 -119
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -6
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +28 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/canonical-integration-operation-store.ts +179 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +80 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +31 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-store-contract.ts +104 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-reference.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +193 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-storage.ts +420 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +41 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +134 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +1657 -95
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +885 -73
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-completion-coalescer.ts +452 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +601 -42
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +371 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +86 -7
- package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +153 -22
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +188 -38
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +28 -13
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +44 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +56 -4
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +2 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +16 -10
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +4 -1
- package/dist/cli/index.js +254 -38
- package/dist/cli/index.mjs +254 -38
- package/dist/{compiler-manifest-DfSnbCTW.d.mts → compiler-manifest-BIqRyj5m.d.mts} +1 -1
- package/dist/{compiler-manifest-DfSnbCTW.d.ts → compiler-manifest-BIqRyj5m.d.ts} +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +231 -35
- package/dist/index.mjs +231 -35
- package/dist/install-integrity.json +31 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +65 -1
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hands source pages to one running map worker pool so the pool never drains
|
|
3
|
+
* between pages. Workers that outrun the appended rows wait here; the page
|
|
4
|
+
* pump appends the next page as soon as the previous one is fully dispatched,
|
|
5
|
+
* so at most one undispatched page and one prepared page are resident.
|
|
6
|
+
*/
|
|
7
|
+
export type RuntimeMapRowFeedSnapshot = {
|
|
8
|
+
appendedRows: number;
|
|
9
|
+
dispatchedRows: number;
|
|
10
|
+
pagesAppended: number;
|
|
11
|
+
closed: boolean;
|
|
12
|
+
failed: boolean;
|
|
13
|
+
workersWaiting: number;
|
|
14
|
+
pumpWaitingForDrain: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const RUNTIME_MAP_ROW_FEED_MAX_WAIT_MS = 30 * 60 * 1000;
|
|
18
|
+
|
|
19
|
+
export class RuntimeMapRowFeedStalledError extends Error {
|
|
20
|
+
readonly snapshot: RuntimeMapRowFeedSnapshot;
|
|
21
|
+
|
|
22
|
+
constructor(input: {
|
|
23
|
+
waiter: 'worker' | 'pump';
|
|
24
|
+
waitMs: number;
|
|
25
|
+
snapshot: RuntimeMapRowFeedSnapshot;
|
|
26
|
+
}) {
|
|
27
|
+
super(
|
|
28
|
+
`Runtime map row feed stalled: ${input.waiter} waited ${input.waitMs} ms ` +
|
|
29
|
+
`(${JSON.stringify(input.snapshot)}).`,
|
|
30
|
+
);
|
|
31
|
+
this.name = 'RuntimeMapRowFeedStalledError';
|
|
32
|
+
this.snapshot = input.snapshot;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type Waiter<T> = {
|
|
37
|
+
resolve: (value: T) => void;
|
|
38
|
+
reject: (error: unknown) => void;
|
|
39
|
+
timer: ReturnType<typeof setTimeout>;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export class RuntimeMapRowFeed {
|
|
43
|
+
#appended = 0;
|
|
44
|
+
#dispatched = 0;
|
|
45
|
+
#pages = 0;
|
|
46
|
+
#closed = false;
|
|
47
|
+
#failure: unknown = null;
|
|
48
|
+
#failed = false;
|
|
49
|
+
readonly #rowWaiters = new Map<Waiter<boolean>, number>();
|
|
50
|
+
#drainWaiter: Waiter<void> | null = null;
|
|
51
|
+
#onAppended: ((fromIndex: number, toIndex: number) => void) | null = null;
|
|
52
|
+
readonly #maxWaitMs: number;
|
|
53
|
+
|
|
54
|
+
constructor(input?: { maxWaitMs?: number }) {
|
|
55
|
+
this.#maxWaitMs =
|
|
56
|
+
input?.maxWaitMs !== undefined &&
|
|
57
|
+
Number.isFinite(input.maxWaitMs) &&
|
|
58
|
+
input.maxWaitMs > 0
|
|
59
|
+
? input.maxWaitMs
|
|
60
|
+
: RUNTIME_MAP_ROW_FEED_MAX_WAIT_MS;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
onAppended(listener: (fromIndex: number, toIndex: number) => void): void {
|
|
64
|
+
this.#onAppended = listener;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
append(rowCount: number): void {
|
|
68
|
+
if (this.#failed) throw this.#failure;
|
|
69
|
+
if (this.#closed) {
|
|
70
|
+
throw new Error('Runtime map row feed is closed; cannot append rows.');
|
|
71
|
+
}
|
|
72
|
+
if (!Number.isInteger(rowCount) || rowCount < 0) {
|
|
73
|
+
throw new Error(`Runtime map row feed append count must be a non-negative integer, got ${String(rowCount)}.`);
|
|
74
|
+
}
|
|
75
|
+
const fromIndex = this.#appended;
|
|
76
|
+
this.#appended += rowCount;
|
|
77
|
+
this.#pages += 1;
|
|
78
|
+
this.#onAppended?.(fromIndex, this.#appended);
|
|
79
|
+
this.#wakeRowWaiters();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
close(): void {
|
|
83
|
+
if (this.#closed || this.#failed) return;
|
|
84
|
+
this.#closed = true;
|
|
85
|
+
this.#wakeRowWaiters();
|
|
86
|
+
this.#settleDrainWaiter();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fail(error: unknown): void {
|
|
90
|
+
if (this.#failed) return;
|
|
91
|
+
this.#failed = true;
|
|
92
|
+
this.#failure = error;
|
|
93
|
+
for (const [waiter] of this.#rowWaiters) {
|
|
94
|
+
clearTimeout(waiter.timer);
|
|
95
|
+
waiter.reject(error);
|
|
96
|
+
}
|
|
97
|
+
this.#rowWaiters.clear();
|
|
98
|
+
if (this.#drainWaiter) {
|
|
99
|
+
clearTimeout(this.#drainWaiter.timer);
|
|
100
|
+
this.#drainWaiter.reject(error);
|
|
101
|
+
this.#drainWaiter = null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get failed(): boolean {
|
|
106
|
+
return this.#failed;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get closed(): boolean {
|
|
110
|
+
return this.#closed;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
markDispatched(count = 1): void {
|
|
114
|
+
this.#dispatched += count;
|
|
115
|
+
if (this.#dispatched > this.#appended) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Runtime map row feed dispatched ${this.#dispatched} rows but only ${this.#appended} were appended.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
this.#settleDrainWaiter();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolves true once row `index` has been appended, false once the feed is
|
|
125
|
+
* closed with no such row. Rejects with the feed's failure.
|
|
126
|
+
*/
|
|
127
|
+
waitForRows(index: number): Promise<boolean> {
|
|
128
|
+
if (this.#failed) return Promise.reject(this.#failure);
|
|
129
|
+
if (index < this.#appended) return Promise.resolve(true);
|
|
130
|
+
if (this.#closed) return Promise.resolve(false);
|
|
131
|
+
return new Promise<boolean>((resolve, reject) => {
|
|
132
|
+
const startedAt = Date.now();
|
|
133
|
+
const waiter: Waiter<boolean> = {
|
|
134
|
+
resolve,
|
|
135
|
+
reject,
|
|
136
|
+
timer: setTimeout(() => {
|
|
137
|
+
this.#rowWaiters.delete(waiter);
|
|
138
|
+
reject(
|
|
139
|
+
new RuntimeMapRowFeedStalledError({
|
|
140
|
+
waiter: 'worker',
|
|
141
|
+
waitMs: Date.now() - startedAt,
|
|
142
|
+
snapshot: this.snapshot(),
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
}, this.#maxWaitMs),
|
|
146
|
+
};
|
|
147
|
+
waiter.timer.unref?.();
|
|
148
|
+
this.#rowWaiters.set(waiter, index);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Resolves once every appended row has been dispatched to a worker. */
|
|
153
|
+
waitUntilDrained(): Promise<void> {
|
|
154
|
+
if (this.#failed) return Promise.reject(this.#failure);
|
|
155
|
+
if (this.#dispatched >= this.#appended) return Promise.resolve();
|
|
156
|
+
if (this.#drainWaiter) {
|
|
157
|
+
return Promise.reject(
|
|
158
|
+
new Error('Runtime map row feed already has a pump waiting to drain.'),
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
return new Promise<void>((resolve, reject) => {
|
|
162
|
+
const startedAt = Date.now();
|
|
163
|
+
this.#drainWaiter = {
|
|
164
|
+
resolve,
|
|
165
|
+
reject,
|
|
166
|
+
timer: setTimeout(() => {
|
|
167
|
+
this.#drainWaiter = null;
|
|
168
|
+
reject(
|
|
169
|
+
new RuntimeMapRowFeedStalledError({
|
|
170
|
+
waiter: 'pump',
|
|
171
|
+
waitMs: Date.now() - startedAt,
|
|
172
|
+
snapshot: this.snapshot(),
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
}, this.#maxWaitMs),
|
|
176
|
+
};
|
|
177
|
+
this.#drainWaiter.timer.unref?.();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
snapshot(): RuntimeMapRowFeedSnapshot {
|
|
182
|
+
return {
|
|
183
|
+
appendedRows: this.#appended,
|
|
184
|
+
dispatchedRows: this.#dispatched,
|
|
185
|
+
pagesAppended: this.#pages,
|
|
186
|
+
closed: this.#closed,
|
|
187
|
+
failed: this.#failed,
|
|
188
|
+
workersWaiting: this.#rowWaiters.size,
|
|
189
|
+
pumpWaitingForDrain: this.#drainWaiter !== null,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#wakeRowWaiters(): void {
|
|
194
|
+
for (const [waiter, index] of this.#rowWaiters) {
|
|
195
|
+
if (index < this.#appended) {
|
|
196
|
+
this.#rowWaiters.delete(waiter);
|
|
197
|
+
clearTimeout(waiter.timer);
|
|
198
|
+
waiter.resolve(true);
|
|
199
|
+
} else if (this.#closed) {
|
|
200
|
+
this.#rowWaiters.delete(waiter);
|
|
201
|
+
clearTimeout(waiter.timer);
|
|
202
|
+
waiter.resolve(false);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#settleDrainWaiter(): void {
|
|
208
|
+
if (!this.#drainWaiter) return;
|
|
209
|
+
if (this.#dispatched < this.#appended && !this.#closed) return;
|
|
210
|
+
const waiter = this.#drainWaiter;
|
|
211
|
+
this.#drainWaiter = null;
|
|
212
|
+
clearTimeout(waiter.timer);
|
|
213
|
+
waiter.resolve();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -24,6 +24,7 @@ export const RUNTIME_OPERATION_CAPABILITIES = {
|
|
|
24
24
|
mark_runtime_step_receipts_queued: 'receipt.write',
|
|
25
25
|
complete_runtime_step_receipt: 'receipt.write',
|
|
26
26
|
complete_runtime_step_receipts: 'receipt.write',
|
|
27
|
+
complete_runtime_step_receipts_by_reference: 'receipt.write',
|
|
27
28
|
release_runtime_step_receipt: 'receipt.write',
|
|
28
29
|
fail_runtime_step_receipt: 'receipt.write',
|
|
29
30
|
fail_runtime_step_receipts: 'receipt.write',
|
|
@@ -54,6 +55,16 @@ export const RUNTIME_OPERATION_CONTRACT: DeployedOperationContract =
|
|
|
54
55
|
deployed.operation({
|
|
55
56
|
id: 'runtime-api-actions',
|
|
56
57
|
actions: RUNTIME_OPERATION_CAPABILITIES,
|
|
58
|
+
olderReceiver: {
|
|
59
|
+
// The runner retains the complete result before attempting this
|
|
60
|
+
// compact completion. An older app receiver reports the action as
|
|
61
|
+
// unsupported, and the adapter retries the established full-payload
|
|
62
|
+
// completion without re-executing the provider call.
|
|
63
|
+
complete_runtime_step_receipts_by_reference: {
|
|
64
|
+
kind: 'equivalent-fallback',
|
|
65
|
+
action: 'complete_runtime_step_receipts',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
57
68
|
});
|
|
58
69
|
|
|
59
70
|
export function runtimeOperationCapability(
|
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AcquireRuntimeReceiptExecutionLockInput,
|
|
3
3
|
ClaimRuntimeStepReceiptInput,
|
|
4
4
|
CompleteRuntimeStepReceiptInput,
|
|
5
|
+
CompleteRuntimeStepReceiptsByReferenceInput,
|
|
5
6
|
ContextOptions,
|
|
6
7
|
FailRuntimeStepReceiptInput,
|
|
7
8
|
ReleaseRuntimeReceiptExecutionLockInput,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
AppRuntimeApiResponseError,
|
|
19
20
|
AppRuntimeApiTransportError,
|
|
20
21
|
claimRuntimeStepReceiptsViaAppRuntime,
|
|
22
|
+
completeRuntimeStepReceiptsByReferenceViaAppRuntime,
|
|
21
23
|
completeRuntimeStepReceiptsViaAppRuntime,
|
|
22
24
|
failRuntimeStepReceiptsViaAppRuntime,
|
|
23
25
|
getRuntimeStepReceiptsViaAppRuntime,
|
|
@@ -31,6 +33,7 @@ import {
|
|
|
31
33
|
import {
|
|
32
34
|
RuntimeReceiptWriter,
|
|
33
35
|
RuntimeReceiptWriterResultCountError,
|
|
36
|
+
writeRuntimeReceiptWithBackpressure,
|
|
34
37
|
} from './runtime-receipt-writer';
|
|
35
38
|
|
|
36
39
|
type ReceiptOutput =
|
|
@@ -42,7 +45,7 @@ type ReceiptOutput =
|
|
|
42
45
|
type ReceiptCommand =
|
|
43
46
|
| {
|
|
44
47
|
kind: 'get';
|
|
45
|
-
input: { key: string; runId: string };
|
|
48
|
+
input: { key: string; runId: string; hydrateOutput?: boolean };
|
|
46
49
|
}
|
|
47
50
|
| {
|
|
48
51
|
kind: 'claim';
|
|
@@ -53,6 +56,11 @@ type ReceiptCommand =
|
|
|
53
56
|
outcome: 'complete';
|
|
54
57
|
input: CompleteRuntimeStepReceiptInput;
|
|
55
58
|
}
|
|
59
|
+
| {
|
|
60
|
+
kind: 'settle';
|
|
61
|
+
outcome: 'complete_reference';
|
|
62
|
+
input: CompleteRuntimeStepReceiptsByReferenceInput['receipts'][number];
|
|
63
|
+
}
|
|
56
64
|
| {
|
|
57
65
|
kind: 'settle';
|
|
58
66
|
outcome: 'fail';
|
|
@@ -99,11 +107,13 @@ type ReceiptHandlerName =
|
|
|
99
107
|
| 'claimRuntimeStepReceipts'
|
|
100
108
|
| 'completeRuntimeStepReceipt'
|
|
101
109
|
| 'completeRuntimeStepReceipts'
|
|
110
|
+
| 'completeRuntimeStepReceiptsByReference'
|
|
102
111
|
| 'releaseRuntimeStepReceipt'
|
|
103
112
|
| 'failRuntimeStepReceipt'
|
|
104
113
|
| 'failRuntimeStepReceipts'
|
|
105
114
|
| 'heartbeatRuntimeStepReceipts'
|
|
106
|
-
| 'skipRuntimeStepReceipt'
|
|
115
|
+
| 'skipRuntimeStepReceipt'
|
|
116
|
+
| 'lastRuntimeStepReceiptCompletionRequestId';
|
|
107
117
|
|
|
108
118
|
export type RuntimeReceiptStoreHandlers = Required<
|
|
109
119
|
Pick<ContextOptions, ReceiptHandlerName>
|
|
@@ -119,15 +129,17 @@ export const RUNTIME_RECEIPT_STORE_RETRY_BUDGET_MS = 5 * 60_000;
|
|
|
119
129
|
* The runner's single Work Receipt Adapter.
|
|
120
130
|
*
|
|
121
131
|
* Receipt-domain batching and gateway transport stay behind this seam. Every
|
|
122
|
-
* command shares one writer
|
|
123
|
-
*
|
|
124
|
-
* one-attempt; this Adapter is the sole retry
|
|
132
|
+
* command shares one writer: operations for one receipt key stay ordered,
|
|
133
|
+
* while independent keys can use its bounded transport pool. The low-level
|
|
134
|
+
* runtime client is explicitly one-attempt; this Adapter is the sole retry
|
|
135
|
+
* owner.
|
|
125
136
|
*/
|
|
126
137
|
export class RuntimeReceiptStoreAdapter {
|
|
127
138
|
readonly handlers: RuntimeReceiptStoreHandlers;
|
|
128
139
|
readonly claimsEstablishExecutionFence = true;
|
|
129
140
|
readonly #writer: RuntimeReceiptWriter<ReceiptCommand, ReceiptOutput>;
|
|
130
141
|
#serial = 0;
|
|
142
|
+
#lastCompletionRequestId: string | null = null;
|
|
131
143
|
|
|
132
144
|
constructor(options: {
|
|
133
145
|
context: WorkerRuntimeApiContext;
|
|
@@ -137,21 +149,76 @@ export class RuntimeReceiptStoreAdapter {
|
|
|
137
149
|
maxBatchBytes?: number;
|
|
138
150
|
targetBatchBytes?: number;
|
|
139
151
|
maxFlushMs?: number;
|
|
152
|
+
maxBufferedItems?: number;
|
|
140
153
|
maxBufferedBytes?: number;
|
|
154
|
+
maxInFlightBatches?: number;
|
|
155
|
+
/** Completion flights may use this many concurrent transports. */
|
|
156
|
+
maxCompletionInFlightBatches?: number;
|
|
157
|
+
/** Control traffic retains this many flights during a completion burst. */
|
|
158
|
+
maxControlInFlightBatches?: number;
|
|
159
|
+
maxCompletionBufferedItems?: number;
|
|
160
|
+
maxCompletionBufferedBytes?: number;
|
|
161
|
+
maxControlBufferedItems?: number;
|
|
162
|
+
maxControlBufferedBytes?: number;
|
|
141
163
|
onRetryTelemetry?: (line: string) => void;
|
|
142
164
|
}) {
|
|
143
165
|
const context: WorkerRuntimeApiContext = {
|
|
144
166
|
...options.context,
|
|
145
167
|
retryPolicy: 'none',
|
|
168
|
+
onResponseMeta: (meta) => {
|
|
169
|
+
if (
|
|
170
|
+
meta.action === 'complete_runtime_step_receipt' ||
|
|
171
|
+
meta.action === 'complete_runtime_step_receipts' ||
|
|
172
|
+
meta.action === 'complete_runtime_step_receipts_by_reference'
|
|
173
|
+
) {
|
|
174
|
+
this.#lastCompletionRequestId = meta.requestId;
|
|
175
|
+
}
|
|
176
|
+
options.context.onResponseMeta?.(meta);
|
|
177
|
+
},
|
|
146
178
|
};
|
|
179
|
+
const usesDedicatedLanes =
|
|
180
|
+
options.maxCompletionInFlightBatches !== undefined ||
|
|
181
|
+
options.maxControlInFlightBatches !== undefined;
|
|
182
|
+
const completionFlights = Math.max(
|
|
183
|
+
1,
|
|
184
|
+
Math.floor(
|
|
185
|
+
options.maxCompletionInFlightBatches ?? options.maxInFlightBatches ?? 1,
|
|
186
|
+
),
|
|
187
|
+
);
|
|
188
|
+
const controlFlights = Math.max(
|
|
189
|
+
1,
|
|
190
|
+
Math.floor(options.maxControlInFlightBatches ?? 1),
|
|
191
|
+
);
|
|
147
192
|
this.#writer = new RuntimeReceiptWriter({
|
|
148
193
|
batchKey: receiptCommandBatchKey,
|
|
194
|
+
...(usesDedicatedLanes
|
|
195
|
+
? {
|
|
196
|
+
batchLane: receiptCommandBatchLane,
|
|
197
|
+
maxInFlightBatches: completionFlights + controlFlights,
|
|
198
|
+
maxInFlightBatchesByLane: {
|
|
199
|
+
completion: completionFlights,
|
|
200
|
+
control: controlFlights,
|
|
201
|
+
},
|
|
202
|
+
maxBufferedByLane: {
|
|
203
|
+
completion: {
|
|
204
|
+
items: options.maxCompletionBufferedItems,
|
|
205
|
+
bytes: options.maxCompletionBufferedBytes,
|
|
206
|
+
},
|
|
207
|
+
control: {
|
|
208
|
+
items: options.maxControlBufferedItems,
|
|
209
|
+
bytes: options.maxControlBufferedBytes,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
}
|
|
213
|
+
: { maxInFlightBatches: options.maxInFlightBatches }),
|
|
214
|
+
orderingKeys: receiptCommandOrderingKeys,
|
|
149
215
|
maxBatchSize: options.maxBatchSize,
|
|
150
216
|
maxBatchBytes:
|
|
151
217
|
options.maxBatchBytes ?? RUNTIME_RECEIPT_GATEWAY_BATCH_MAX_BYTES,
|
|
152
218
|
targetBatchBytes:
|
|
153
219
|
options.targetBatchBytes ?? RUNTIME_RECEIPT_WRITER_TARGET_BATCH_BYTES,
|
|
154
220
|
maxFlushMs: options.maxFlushMs,
|
|
221
|
+
maxBufferedItems: options.maxBufferedItems,
|
|
155
222
|
maxBufferedBytes: options.maxBufferedBytes,
|
|
156
223
|
maxRetryElapsedMs: RUNTIME_RECEIPT_STORE_RETRY_BUDGET_MS,
|
|
157
224
|
classifyRetryableError: classifyReceiptRetry,
|
|
@@ -171,12 +238,12 @@ export class RuntimeReceiptStoreAdapter {
|
|
|
171
238
|
}),
|
|
172
239
|
});
|
|
173
240
|
|
|
174
|
-
const write = <Output extends ReceiptOutput>(
|
|
241
|
+
const write = async <Output extends ReceiptOutput>(
|
|
175
242
|
command: ReceiptCommand,
|
|
176
243
|
): Promise<Output> =>
|
|
177
|
-
this.#writer
|
|
244
|
+
(await writeRuntimeReceiptWithBackpressure(this.#writer, command, {
|
|
178
245
|
signal: options.context.signal,
|
|
179
|
-
}) as
|
|
246
|
+
})) as Output;
|
|
180
247
|
const writeMany = <Output extends ReceiptOutput>(
|
|
181
248
|
commands: readonly ReceiptCommand[],
|
|
182
249
|
): Promise<Output[]> =>
|
|
@@ -195,16 +262,24 @@ export class RuntimeReceiptStoreAdapter {
|
|
|
195
262
|
input,
|
|
196
263
|
serial: this.#nextSerial(),
|
|
197
264
|
}),
|
|
198
|
-
getRuntimeStepReceipt: ({ key }) =>
|
|
265
|
+
getRuntimeStepReceipt: ({ key, hydrateOutput }) =>
|
|
199
266
|
write({
|
|
200
267
|
kind: 'get',
|
|
201
|
-
input: {
|
|
268
|
+
input: {
|
|
269
|
+
key,
|
|
270
|
+
runId: options.runId,
|
|
271
|
+
...(hydrateOutput === false ? { hydrateOutput: false } : {}),
|
|
272
|
+
},
|
|
202
273
|
}),
|
|
203
|
-
getRuntimeStepReceipts: ({ keys }) =>
|
|
274
|
+
getRuntimeStepReceipts: ({ keys, hydrateOutput }) =>
|
|
204
275
|
writeMany(
|
|
205
276
|
keys.map((key) => ({
|
|
206
277
|
kind: 'get' as const,
|
|
207
|
-
input: {
|
|
278
|
+
input: {
|
|
279
|
+
key,
|
|
280
|
+
runId: options.runId,
|
|
281
|
+
...(hydrateOutput === false ? { hydrateOutput: false } : {}),
|
|
282
|
+
},
|
|
208
283
|
})),
|
|
209
284
|
),
|
|
210
285
|
claimRuntimeStepReceipt: (input) => write({ kind: 'claim', input }),
|
|
@@ -220,6 +295,9 @@ export class RuntimeReceiptStoreAdapter {
|
|
|
220
295
|
reclaimRunning: input.reclaimRunning,
|
|
221
296
|
forceRefresh: input.forceRefresh,
|
|
222
297
|
forceFailedRefresh: input.forceFailedRefresh,
|
|
298
|
+
...(input.hydrateOutput === false
|
|
299
|
+
? { hydrateOutput: false }
|
|
300
|
+
: {}),
|
|
223
301
|
...(input.leaseIds ? { leaseId: input.leaseIds[index] } : {}),
|
|
224
302
|
},
|
|
225
303
|
})),
|
|
@@ -234,6 +312,14 @@ export class RuntimeReceiptStoreAdapter {
|
|
|
234
312
|
input,
|
|
235
313
|
})),
|
|
236
314
|
),
|
|
315
|
+
completeRuntimeStepReceiptsByReference: ({ receipts }) =>
|
|
316
|
+
writeMany(
|
|
317
|
+
receipts.map((input) => ({
|
|
318
|
+
kind: 'settle' as const,
|
|
319
|
+
outcome: 'complete_reference' as const,
|
|
320
|
+
input,
|
|
321
|
+
})),
|
|
322
|
+
),
|
|
237
323
|
releaseRuntimeStepReceipt: (input) =>
|
|
238
324
|
write({
|
|
239
325
|
kind: 'settle',
|
|
@@ -270,6 +356,8 @@ export class RuntimeReceiptStoreAdapter {
|
|
|
270
356
|
input,
|
|
271
357
|
serial: this.#nextSerial(),
|
|
272
358
|
}),
|
|
359
|
+
lastRuntimeStepReceiptCompletionRequestId: () =>
|
|
360
|
+
this.#lastCompletionRequestId,
|
|
273
361
|
};
|
|
274
362
|
}
|
|
275
363
|
|
|
@@ -363,7 +451,7 @@ function emitReceiptWriterRetryTelemetry(input: {
|
|
|
363
451
|
elapsedMs: event.elapsedMs,
|
|
364
452
|
retryAfterMs: event.retryAfterMs,
|
|
365
453
|
queued: event.queued,
|
|
366
|
-
|
|
454
|
+
bufferedItems: event.bufferedItems,
|
|
367
455
|
bufferedBytes: event.bufferedBytes,
|
|
368
456
|
...(event.error === undefined
|
|
369
457
|
? { failureKind: null }
|
|
@@ -398,7 +486,9 @@ function receiptCommandBatchKey(command: ReceiptCommand): string {
|
|
|
398
486
|
command.input.leaseId !== undefined,
|
|
399
487
|
]);
|
|
400
488
|
case 'settle':
|
|
401
|
-
return command.outcome === 'complete' ||
|
|
489
|
+
return command.outcome === 'complete' ||
|
|
490
|
+
command.outcome === 'complete_reference' ||
|
|
491
|
+
command.outcome === 'fail'
|
|
402
492
|
? JSON.stringify([command.kind, command.outcome, command.input.runId])
|
|
403
493
|
: `${command.kind}:${command.outcome}:${command.serial}`;
|
|
404
494
|
case 'heartbeat':
|
|
@@ -413,6 +503,37 @@ function receiptCommandBatchKey(command: ReceiptCommand): string {
|
|
|
413
503
|
}
|
|
414
504
|
}
|
|
415
505
|
|
|
506
|
+
function receiptCommandBatchLane(
|
|
507
|
+
command: ReceiptCommand,
|
|
508
|
+
): 'completion' | 'control' {
|
|
509
|
+
return command.kind === 'settle' &&
|
|
510
|
+
(command.outcome === 'complete' ||
|
|
511
|
+
command.outcome === 'complete_reference' ||
|
|
512
|
+
command.outcome === 'fail')
|
|
513
|
+
? 'completion'
|
|
514
|
+
: 'control';
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* The gateway conditionally owns every receipt transition, but same-receipt
|
|
519
|
+
* commands still travel in program order. Different receipt keys are
|
|
520
|
+
* independent and can safely occupy the shared bounded transport pool.
|
|
521
|
+
*/
|
|
522
|
+
function receiptCommandOrderingKeys(
|
|
523
|
+
command: ReceiptCommand,
|
|
524
|
+
): readonly string[] {
|
|
525
|
+
switch (command.kind) {
|
|
526
|
+
case 'get':
|
|
527
|
+
case 'claim':
|
|
528
|
+
case 'heartbeat':
|
|
529
|
+
case 'acquire_execution_lock':
|
|
530
|
+
case 'release_execution_lock':
|
|
531
|
+
return [command.input.key];
|
|
532
|
+
case 'settle':
|
|
533
|
+
return [command.input.key];
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
416
537
|
function classifyReceiptRetry(error: unknown): { retryAfterMs: number } | null {
|
|
417
538
|
if (isAppRuntimeApiCapacityError(error)) {
|
|
418
539
|
return { retryAfterMs: error.retryAfterMs };
|
|
@@ -443,6 +564,12 @@ async function sendReceiptCommands(input: {
|
|
|
443
564
|
playName: input.playName,
|
|
444
565
|
runId: first.input.runId,
|
|
445
566
|
keys: commands.map((command) => command.input.key),
|
|
567
|
+
// A mixed writer batch must preserve normal full reads. The manifest
|
|
568
|
+
// probe safely falls back to its byte-admitted path when it receives a
|
|
569
|
+
// body, so never omit an output a concurrent caller requested.
|
|
570
|
+
...(commands.every((command) => command.input.hydrateOutput === false)
|
|
571
|
+
? { hydrateOutput: false }
|
|
572
|
+
: {}),
|
|
446
573
|
});
|
|
447
574
|
}
|
|
448
575
|
case 'claim': {
|
|
@@ -463,6 +590,12 @@ async function sendReceiptCommands(input: {
|
|
|
463
590
|
reclaimRunning: first.input.reclaimRunning,
|
|
464
591
|
forceRefresh: first.input.forceRefresh,
|
|
465
592
|
forceFailedRefresh: first.input.forceFailedRefresh,
|
|
593
|
+
// A mixed writer batch must retain a full body for callers that
|
|
594
|
+
// requested one. Manifest callers detect such a body and re-enter the
|
|
595
|
+
// byte-admitted hydration path before using it.
|
|
596
|
+
...(commands.every((command) => command.input.hydrateOutput === false)
|
|
597
|
+
? { hydrateOutput: false }
|
|
598
|
+
: {}),
|
|
466
599
|
});
|
|
467
600
|
}
|
|
468
601
|
case 'settle':
|
|
@@ -478,6 +611,20 @@ async function sendReceiptCommands(input: {
|
|
|
478
611
|
receipts: commands.map((command) => command.input),
|
|
479
612
|
});
|
|
480
613
|
}
|
|
614
|
+
case 'complete_reference': {
|
|
615
|
+
const commands = input.commands as readonly Extract<
|
|
616
|
+
ReceiptCommand,
|
|
617
|
+
{ kind: 'settle'; outcome: 'complete_reference' }
|
|
618
|
+
>[];
|
|
619
|
+
return await completeRuntimeStepReceiptsByReferenceViaAppRuntime(
|
|
620
|
+
input.context,
|
|
621
|
+
{
|
|
622
|
+
playName: input.playName,
|
|
623
|
+
runId: first.input.runId,
|
|
624
|
+
receipts: commands.map((command) => command.input),
|
|
625
|
+
},
|
|
626
|
+
);
|
|
627
|
+
}
|
|
481
628
|
case 'fail': {
|
|
482
629
|
const commands = input.commands as readonly Extract<
|
|
483
630
|
ReceiptCommand,
|