deepline 0.3.128 → 0.3.130
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/daytona-sandbox-janitor.ts +4 -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 +114 -4
- 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/absurd.ts +28 -8
- 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 +146 -15
- 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 +904 -77
- 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 +250 -38
- package/dist/cli/index.mjs +250 -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
|
@@ -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,
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An immutable body stored outside a runtime receipt row.
|
|
3
|
+
*
|
|
4
|
+
* Receipt rows remain the authority for whether an outcome exists. A reference
|
|
5
|
+
* carries bytes only; it is never a cache miss, execution lease, or permission
|
|
6
|
+
* to run a provider operation again.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* R2 owns a referenced receipt's complete result body. These are the small,
|
|
10
|
+
* selected fields that may travel with its manifest for routing, presentation,
|
|
11
|
+
* and admission without redeeming that body.
|
|
12
|
+
*/
|
|
13
|
+
export const RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_BYTES = 16 * 1024;
|
|
14
|
+
export const RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_KEYS = 32;
|
|
15
|
+
const RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_DEPTH = 16;
|
|
16
|
+
|
|
17
|
+
export type RuntimeReceiptValueInlineValue =
|
|
18
|
+
| string
|
|
19
|
+
| number
|
|
20
|
+
| boolean
|
|
21
|
+
| null
|
|
22
|
+
| RuntimeReceiptValueInlineValue[]
|
|
23
|
+
| { [key: string]: RuntimeReceiptValueInlineValue };
|
|
24
|
+
|
|
25
|
+
export type RuntimeReceiptValueInlineFields = Record<
|
|
26
|
+
string,
|
|
27
|
+
RuntimeReceiptValueInlineValue
|
|
28
|
+
>;
|
|
29
|
+
|
|
30
|
+
export type RuntimeReceiptValueReference = {
|
|
31
|
+
storage: 'r2';
|
|
32
|
+
/**
|
|
33
|
+
* New manifests use the named JSON codec. The compatibility reader accepts
|
|
34
|
+
* the already-written legacy spelling without promoting a numeric protocol.
|
|
35
|
+
*/
|
|
36
|
+
codec: 'json' | 'json-v1';
|
|
37
|
+
key: string;
|
|
38
|
+
digest: string;
|
|
39
|
+
byteLength: number;
|
|
40
|
+
/** SHA-256 binding for the authenticated organization, never its raw id. */
|
|
41
|
+
orgBinding: string;
|
|
42
|
+
/** SHA-256 binding for the receipt key that owns this value. */
|
|
43
|
+
receiptBinding: string;
|
|
44
|
+
/**
|
|
45
|
+
* Bounded selected fields beside an R2 body. Never a second full result.
|
|
46
|
+
* This field is additive so readers that predate it still use the reference.
|
|
47
|
+
*/
|
|
48
|
+
inlineFields?: RuntimeReceiptValueInlineFields;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Canonicalize the small manifest payload before it crosses a receipt boundary.
|
|
53
|
+
* It is intentionally stricter than JSON.stringify: undefined values, Dates,
|
|
54
|
+
* non-finite numbers, and custom objects fail rather than changing meaning.
|
|
55
|
+
*/
|
|
56
|
+
export function normalizeRuntimeReceiptValueInlineFields(
|
|
57
|
+
value: unknown,
|
|
58
|
+
): RuntimeReceiptValueInlineFields {
|
|
59
|
+
if (!isPlainRecord(value)) {
|
|
60
|
+
throw new Error('Runtime receipt inline fields must be a plain object.');
|
|
61
|
+
}
|
|
62
|
+
const keys = Object.keys(value);
|
|
63
|
+
if (keys.length > RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_KEYS) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Runtime receipt inline fields exceed ${RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_KEYS} keys.`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
const copied = copyInlineValue(value, '$', new Set<object>(), 0);
|
|
69
|
+
if (!isPlainRecord(copied)) {
|
|
70
|
+
throw new Error('Runtime receipt inline fields must normalize to an object.');
|
|
71
|
+
}
|
|
72
|
+
const serialized = JSON.stringify(copied);
|
|
73
|
+
const bytes = new TextEncoder().encode(serialized).byteLength;
|
|
74
|
+
if (bytes > RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_BYTES) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Runtime receipt inline fields exceed ${RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_BYTES} bytes.`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return copied;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function isRuntimeReceiptValueReference(
|
|
83
|
+
value: unknown,
|
|
84
|
+
): value is RuntimeReceiptValueReference {
|
|
85
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
86
|
+
const candidate = value as Record<string, unknown>;
|
|
87
|
+
return (
|
|
88
|
+
candidate.storage === 'r2' &&
|
|
89
|
+
(candidate.codec === 'json' || candidate.codec === 'json-v1') &&
|
|
90
|
+
typeof candidate.key === 'string' &&
|
|
91
|
+
candidate.key.length > 0 &&
|
|
92
|
+
/^[a-f0-9]{64}$/i.test(String(candidate.digest ?? '')) &&
|
|
93
|
+
Number.isSafeInteger(candidate.byteLength) &&
|
|
94
|
+
Number(candidate.byteLength) >= 0 &&
|
|
95
|
+
/^[a-f0-9]{64}$/i.test(String(candidate.orgBinding ?? '')) &&
|
|
96
|
+
/^[a-f0-9]{64}$/i.test(String(candidate.receiptBinding ?? '')) &&
|
|
97
|
+
(candidate.inlineFields === undefined ||
|
|
98
|
+
isRuntimeReceiptValueInlineFields(candidate.inlineFields))
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isRuntimeReceiptValueInlineFields(
|
|
103
|
+
value: unknown,
|
|
104
|
+
): value is RuntimeReceiptValueInlineFields {
|
|
105
|
+
try {
|
|
106
|
+
normalizeRuntimeReceiptValueInlineFields(value);
|
|
107
|
+
return true;
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function copyInlineValue(
|
|
114
|
+
value: unknown,
|
|
115
|
+
path: string,
|
|
116
|
+
ancestors: Set<object>,
|
|
117
|
+
depth: number,
|
|
118
|
+
): RuntimeReceiptValueInlineValue {
|
|
119
|
+
if (depth > RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_DEPTH) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`Runtime receipt inline field ${path} exceeds ${RUNTIME_RECEIPT_VALUE_INLINE_FIELDS_MAX_DEPTH} nested levels.`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (value === null) return null;
|
|
125
|
+
if (typeof value === 'string' || typeof value === 'boolean') return value;
|
|
126
|
+
if (typeof value === 'number') {
|
|
127
|
+
if (Number.isFinite(value)) return value;
|
|
128
|
+
throw new Error(`Runtime receipt inline field ${path} must be finite.`);
|
|
129
|
+
}
|
|
130
|
+
if (Array.isArray(value)) {
|
|
131
|
+
if (ancestors.has(value)) {
|
|
132
|
+
throw new Error(`Runtime receipt inline field ${path} cannot be cyclic.`);
|
|
133
|
+
}
|
|
134
|
+
ancestors.add(value);
|
|
135
|
+
try {
|
|
136
|
+
return value.map((entry, index) =>
|
|
137
|
+
copyInlineValue(entry, `${path}[${index}]`, ancestors, depth + 1),
|
|
138
|
+
);
|
|
139
|
+
} finally {
|
|
140
|
+
ancestors.delete(value);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (isPlainRecord(value)) {
|
|
144
|
+
if (ancestors.has(value)) {
|
|
145
|
+
throw new Error(`Runtime receipt inline field ${path} cannot be cyclic.`);
|
|
146
|
+
}
|
|
147
|
+
ancestors.add(value);
|
|
148
|
+
try {
|
|
149
|
+
const copied: Record<string, RuntimeReceiptValueInlineValue> = {};
|
|
150
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
151
|
+
copied[key] = copyInlineValue(
|
|
152
|
+
entry,
|
|
153
|
+
`${path}.${key}`,
|
|
154
|
+
ancestors,
|
|
155
|
+
depth + 1,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return copied;
|
|
159
|
+
} finally {
|
|
160
|
+
ancestors.delete(value);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Runtime receipt inline field ${path} must be JSON data, not ${
|
|
165
|
+
value === undefined ? 'undefined' : typeof value
|
|
166
|
+
}.`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
171
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
172
|
+
const prototype = Object.getPrototypeOf(value);
|
|
173
|
+
return prototype === Object.prototype || prototype === null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export class RuntimeReceiptValueReadError extends Error {
|
|
177
|
+
constructor(
|
|
178
|
+
readonly code: 'missing' | 'corrupt' | 'unavailable' | 'scope_mismatch',
|
|
179
|
+
message: string,
|
|
180
|
+
) {
|
|
181
|
+
super(message);
|
|
182
|
+
this.name = 'RuntimeReceiptValueReadError';
|
|
183
|
+
}
|
|
184
|
+
}
|