deepline 0.1.243 → 0.1.245
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +5 -25
- package/dist/bundling-sources/sdk/src/release.ts +25 -26
- package/dist/bundling-sources/sdk/src/types.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/backend.ts +2 -21
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -6
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +6 -13
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +9 -26
- package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +1 -2
- package/dist/bundling-sources/shared_libs/play-runtime/map-row-identity.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +191 -29
- package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +1 -36
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +0 -7
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1 -12
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +5 -15
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +6 -21
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +3 -4
- package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +16 -29
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -8
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +21 -712
- package/dist/bundling-sources/shared_libs/plays/bundling/limits.ts +1 -18
- package/dist/cli/index.js +28 -71
- package/dist/cli/index.mjs +28 -71
- package/dist/{compiler-manifest-CYcwzSOJ.d.ts → compiler-manifest-DlE7dnRm.d.mts} +2 -8
- package/dist/{compiler-manifest-CYcwzSOJ.d.mts → compiler-manifest-DlE7dnRm.d.ts} +2 -8
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +23 -22
- package/dist/index.mjs +23 -22
- package/dist/plays/bundle-play-file.d.mts +7 -22
- package/dist/plays/bundle-play-file.d.ts +7 -22
- package/dist/plays/bundle-play-file.mjs +26 -614
- package/package.json +2 -2
- package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +0 -4504
- package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +0 -1386
- package/dist/bundling-sources/apps/play-runner-workers/src/durable-object-deploy-handoff.ts +0 -30
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +0 -8385
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +0 -21
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +0 -251
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/coordinator-progress.ts +0 -289
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -85
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +0 -23
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -528
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -229
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/ledger-event-batches.ts +0 -81
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/live-progress.ts +0 -22
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -920
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +0 -90
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/output-datasets.ts +0 -475
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +0 -570
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/result-dataset-persistence.ts +0 -50
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -5
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/run-work-dispatcher.ts +0 -519
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -107
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +0 -2541
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -7
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +0 -227
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/work-budget.ts +0 -130
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/worker-platform-budget.ts +0 -39
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/workflow-preview.ts +0 -26
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime-api-retry.ts +0 -23
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-instance-create.ts +0 -47
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +0 -167
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry.ts +0 -91
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +0 -329
- package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -240
- package/dist/bundling-sources/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -252
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -217
|
@@ -1,570 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildScopedWorkReceiptKey,
|
|
3
|
-
type WorkReceipt,
|
|
4
|
-
type WorkReceiptBatchMarkRunningCommand,
|
|
5
|
-
type WorkReceiptClaim,
|
|
6
|
-
type WorkReceiptCommand,
|
|
7
|
-
type WorkReceiptGetCommand,
|
|
8
|
-
type WorkReceiptStatus,
|
|
9
|
-
} from '../../../../shared_libs/play-runtime/work-receipts';
|
|
10
|
-
import type { ExecutionLedgerStore } from '../../../../shared_libs/play-runtime/execution-ledger-store';
|
|
11
|
-
import {
|
|
12
|
-
PLAY_RUNTIME_WORK_RECEIPT_LEASE_TTL_MS,
|
|
13
|
-
runtimeLeaseHeartbeatIntervalMs,
|
|
14
|
-
} from '../../../../shared_libs/play-runtime/lease-policy';
|
|
15
|
-
import {
|
|
16
|
-
isPlayExecutionSuspendedError,
|
|
17
|
-
isPlayRowExecutionSuspendedError,
|
|
18
|
-
} from '../../../../shared_libs/play-runtime/suspension';
|
|
19
|
-
import { runtimeReceiptFailureKindForError } from '../../../../shared_libs/play-runtime/durable-receipt-execution';
|
|
20
|
-
import type { WorkerWorkBudgetMeter } from './work-budget';
|
|
21
|
-
|
|
22
|
-
export type RuntimeReceiptStatus = WorkReceiptStatus;
|
|
23
|
-
|
|
24
|
-
export type WorkerRuntimeReceipt = WorkReceipt;
|
|
25
|
-
|
|
26
|
-
export type WorkerRuntimeReceiptCommand = WorkReceiptCommand;
|
|
27
|
-
export type WorkerRuntimeReceiptGetCommand = WorkReceiptGetCommand;
|
|
28
|
-
|
|
29
|
-
export type WorkerRuntimeReceiptClaim = WorkReceiptClaim;
|
|
30
|
-
|
|
31
|
-
export type WorkerRuntimeReceiptStore = Pick<
|
|
32
|
-
ExecutionLedgerStore,
|
|
33
|
-
'claimReceipt' | 'completeReceipt' | 'failReceipt'
|
|
34
|
-
> &
|
|
35
|
-
Partial<
|
|
36
|
-
Pick<
|
|
37
|
-
ExecutionLedgerStore,
|
|
38
|
-
| 'getReceipt'
|
|
39
|
-
| 'claimReceipts'
|
|
40
|
-
| 'completeReceipts'
|
|
41
|
-
| 'failReceipts'
|
|
42
|
-
| 'releaseReceipt'
|
|
43
|
-
| 'heartbeatReceipts'
|
|
44
|
-
>
|
|
45
|
-
> & {
|
|
46
|
-
markReceiptsRunning?: (
|
|
47
|
-
input: WorkReceiptBatchMarkRunningCommand,
|
|
48
|
-
) => Promise<Array<WorkReceipt | null>>;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
export type WorkerRuntimeReceiptMarkRunningCommand =
|
|
52
|
-
WorkReceiptBatchMarkRunningCommand;
|
|
53
|
-
|
|
54
|
-
type RuntimeReceiptContext = {
|
|
55
|
-
orgId?: string | null;
|
|
56
|
-
playName: string;
|
|
57
|
-
runId: string;
|
|
58
|
-
runAttempt?: number | null;
|
|
59
|
-
key: string;
|
|
60
|
-
receiptStore: WorkerRuntimeReceiptStore;
|
|
61
|
-
budgetMeter?: WorkerWorkBudgetMeter;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type WorkerRuntimeReceiptExecutionContext = {
|
|
65
|
-
leaseId: string | null;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
type WorkerRuntimeReceiptExecute<T> = (
|
|
69
|
-
context: WorkerRuntimeReceiptExecutionContext,
|
|
70
|
-
wasFailed: boolean,
|
|
71
|
-
) => Promise<T> | T;
|
|
72
|
-
|
|
73
|
-
const WORKER_RECEIPT_DEFAULT_WAIT_MS = 300_000;
|
|
74
|
-
const WORKER_RECEIPT_WAIT_DELAY_MS = 250;
|
|
75
|
-
const WORKER_RECEIPT_WAIT_MAX_ATTEMPTS = Math.ceil(
|
|
76
|
-
WORKER_RECEIPT_DEFAULT_WAIT_MS / WORKER_RECEIPT_WAIT_DELAY_MS,
|
|
77
|
-
);
|
|
78
|
-
const WORKER_RECEIPT_HEARTBEAT_INTERVAL_MS = runtimeLeaseHeartbeatIntervalMs(
|
|
79
|
-
PLAY_RUNTIME_WORK_RECEIPT_LEASE_TTL_MS,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
class RuntimeReceiptWaitTimeoutError extends Error {
|
|
83
|
-
constructor(key: string) {
|
|
84
|
-
super(`Timed out waiting for runtime receipt ${key}.`);
|
|
85
|
-
this.name = 'RuntimeReceiptWaitTimeoutError';
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export class RuntimeLeaseLostError extends Error {
|
|
90
|
-
readonly keys: string[];
|
|
91
|
-
readonly runId: string;
|
|
92
|
-
readonly leaseId: string;
|
|
93
|
-
|
|
94
|
-
constructor(input: {
|
|
95
|
-
keys: string[];
|
|
96
|
-
runId: string;
|
|
97
|
-
leaseId: string;
|
|
98
|
-
cause?: unknown;
|
|
99
|
-
}) {
|
|
100
|
-
const keySummary =
|
|
101
|
-
input.keys.length === 1
|
|
102
|
-
? input.keys[0]!
|
|
103
|
-
: `${input.keys.length} receipts`;
|
|
104
|
-
super(
|
|
105
|
-
`Runtime receipt ${keySummary} lost lease ${input.leaseId} before execution finished.`,
|
|
106
|
-
{ cause: input.cause },
|
|
107
|
-
);
|
|
108
|
-
this.name = 'RuntimeLeaseLostError';
|
|
109
|
-
this.keys = input.keys;
|
|
110
|
-
this.runId = input.runId;
|
|
111
|
-
this.leaseId = input.leaseId;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function scopedReceiptKey(input: {
|
|
116
|
-
orgId?: string | null;
|
|
117
|
-
playName: string;
|
|
118
|
-
key: string;
|
|
119
|
-
}): string {
|
|
120
|
-
const orgId = input.orgId?.trim() || 'org';
|
|
121
|
-
if (input.key.startsWith(`ctx:${orgId}:`)) {
|
|
122
|
-
return input.key;
|
|
123
|
-
}
|
|
124
|
-
return buildScopedWorkReceiptKey(input);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function receiptOutput<T>(receipt: WorkerRuntimeReceipt): T {
|
|
128
|
-
return receipt.output as T;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function errorMessage(error: unknown): string {
|
|
132
|
-
return error instanceof Error ? error.message : String(error);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function waitForReusableReceipt<T>(input: {
|
|
136
|
-
key: string;
|
|
137
|
-
playName: string;
|
|
138
|
-
receiptStore: WorkerRuntimeReceiptStore;
|
|
139
|
-
maxAttempts?: number;
|
|
140
|
-
delayMs?: number;
|
|
141
|
-
}): Promise<T> {
|
|
142
|
-
if (!input.receiptStore.getReceipt) {
|
|
143
|
-
throw new Error(
|
|
144
|
-
`Runtime receipt ${input.key} wait requires read-only receipt lookup.`,
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
const maxAttempts = input.maxAttempts ?? WORKER_RECEIPT_WAIT_MAX_ATTEMPTS;
|
|
148
|
-
const delayMs = input.delayMs ?? WORKER_RECEIPT_WAIT_DELAY_MS;
|
|
149
|
-
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
150
|
-
if (attempt > 0) {
|
|
151
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
152
|
-
}
|
|
153
|
-
const receipt = await input.receiptStore.getReceipt({
|
|
154
|
-
playName: input.playName,
|
|
155
|
-
key: input.key,
|
|
156
|
-
});
|
|
157
|
-
if (receipt?.status === 'completed' || receipt?.status === 'skipped') {
|
|
158
|
-
return receiptOutput<T>(receipt);
|
|
159
|
-
}
|
|
160
|
-
if (receipt?.status === 'failed') {
|
|
161
|
-
throw new Error(
|
|
162
|
-
`Runtime receipt ${input.key} failed while waiting: ${receipt.error ?? 'unknown error'}`,
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
throw new RuntimeReceiptWaitTimeoutError(input.key);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
type WorkerRuntimeReceiptHeartbeatTarget = {
|
|
170
|
-
key: string | null | undefined;
|
|
171
|
-
leaseId: string | null | undefined;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
function heartbeatGroups(
|
|
175
|
-
targets: WorkerRuntimeReceiptHeartbeatTarget[],
|
|
176
|
-
): Array<{ leaseId: string; keys: string[] }> {
|
|
177
|
-
const byLeaseId = new Map<string, string[]>();
|
|
178
|
-
for (const target of targets) {
|
|
179
|
-
const key = target.key?.trim();
|
|
180
|
-
const leaseId = target.leaseId?.trim();
|
|
181
|
-
if (!key || !leaseId) continue;
|
|
182
|
-
const keys = byLeaseId.get(leaseId);
|
|
183
|
-
if (keys) {
|
|
184
|
-
keys.push(key);
|
|
185
|
-
} else {
|
|
186
|
-
byLeaseId.set(leaseId, [key]);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return Array.from(byLeaseId, ([leaseId, keys]) => ({ leaseId, keys }));
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function buildLeaseLostError(input: {
|
|
193
|
-
keys: string[];
|
|
194
|
-
runId: string;
|
|
195
|
-
leaseId: string;
|
|
196
|
-
cause?: unknown;
|
|
197
|
-
}): RuntimeLeaseLostError {
|
|
198
|
-
return new RuntimeLeaseLostError(input);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function receiptHeartbeatStillOwnsOrSettled(input: {
|
|
202
|
-
receipt: WorkerRuntimeReceipt | null | undefined;
|
|
203
|
-
leaseId: string;
|
|
204
|
-
}): boolean {
|
|
205
|
-
const { receipt } = input;
|
|
206
|
-
if (!receipt) return false;
|
|
207
|
-
if (receipt.status === 'completed' || receipt.status === 'skipped') {
|
|
208
|
-
return true;
|
|
209
|
-
}
|
|
210
|
-
if (receipt.status !== 'running' && receipt.status !== 'queued') {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
return receipt.leaseId === input.leaseId;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export async function executeWithWorkerReceiptHeartbeats<T>(input: {
|
|
217
|
-
playName: string;
|
|
218
|
-
runId: string;
|
|
219
|
-
runAttempt?: number | null;
|
|
220
|
-
receiptStore?: WorkerRuntimeReceiptStore | null;
|
|
221
|
-
budgetMeter?: WorkerWorkBudgetMeter;
|
|
222
|
-
targets: WorkerRuntimeReceiptHeartbeatTarget[];
|
|
223
|
-
heartbeatIntervalMs?: number;
|
|
224
|
-
execute: () => Promise<T> | T;
|
|
225
|
-
}): Promise<T> {
|
|
226
|
-
const groups = heartbeatGroups(input.targets);
|
|
227
|
-
const heartbeatReceipts = input.receiptStore?.heartbeatReceipts;
|
|
228
|
-
if (groups.length === 0 || !heartbeatReceipts) {
|
|
229
|
-
return await input.execute();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const heartbeatIntervalMs =
|
|
233
|
-
input.heartbeatIntervalMs ?? WORKER_RECEIPT_HEARTBEAT_INTERVAL_MS;
|
|
234
|
-
if (!Number.isFinite(heartbeatIntervalMs) || heartbeatIntervalMs <= 0) {
|
|
235
|
-
throw new Error('Runtime receipt heartbeat interval must be positive.');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
let stopped = false;
|
|
239
|
-
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
240
|
-
let rejectLeaseLost!: (error: RuntimeLeaseLostError) => void;
|
|
241
|
-
const leaseLost = new Promise<never>((_, reject) => {
|
|
242
|
-
rejectLeaseLost = reject;
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
const stop = () => {
|
|
246
|
-
stopped = true;
|
|
247
|
-
if (timeout !== null) {
|
|
248
|
-
clearTimeout(timeout);
|
|
249
|
-
timeout = null;
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const heartbeatOnce = async () => {
|
|
254
|
-
for (const group of groups) {
|
|
255
|
-
input.budgetMeter?.count('heartbeat');
|
|
256
|
-
const receipts = await heartbeatReceipts({
|
|
257
|
-
playName: input.playName,
|
|
258
|
-
runId: input.runId,
|
|
259
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
260
|
-
leaseId: group.leaseId,
|
|
261
|
-
keys: group.keys,
|
|
262
|
-
});
|
|
263
|
-
for (let index = 0; index < group.keys.length; index += 1) {
|
|
264
|
-
const receipt = receipts[index];
|
|
265
|
-
if (
|
|
266
|
-
!receiptHeartbeatStillOwnsOrSettled({
|
|
267
|
-
receipt,
|
|
268
|
-
leaseId: group.leaseId,
|
|
269
|
-
})
|
|
270
|
-
) {
|
|
271
|
-
throw buildLeaseLostError({
|
|
272
|
-
keys: group.keys,
|
|
273
|
-
runId: input.runId,
|
|
274
|
-
leaseId: group.leaseId,
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const schedule = () => {
|
|
282
|
-
timeout = setTimeout(() => {
|
|
283
|
-
void (async () => {
|
|
284
|
-
try {
|
|
285
|
-
await heartbeatOnce();
|
|
286
|
-
} catch (error) {
|
|
287
|
-
stop();
|
|
288
|
-
if (error instanceof RuntimeLeaseLostError) {
|
|
289
|
-
rejectLeaseLost(error);
|
|
290
|
-
} else {
|
|
291
|
-
rejectLeaseLost(
|
|
292
|
-
buildLeaseLostError({
|
|
293
|
-
keys: groups.flatMap((group) => group.keys),
|
|
294
|
-
runId: input.runId,
|
|
295
|
-
leaseId: groups[0]?.leaseId ?? 'unknown',
|
|
296
|
-
cause: error,
|
|
297
|
-
}),
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
if (!stopped) {
|
|
303
|
-
schedule();
|
|
304
|
-
}
|
|
305
|
-
})();
|
|
306
|
-
}, heartbeatIntervalMs);
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
await heartbeatOnce();
|
|
310
|
-
schedule();
|
|
311
|
-
const execution = Promise.resolve().then(input.execute);
|
|
312
|
-
execution.catch(() => {});
|
|
313
|
-
try {
|
|
314
|
-
return await Promise.race([execution, leaseLost]);
|
|
315
|
-
} finally {
|
|
316
|
-
stop();
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function shouldRepairSameRunRunningReceipt(input: {
|
|
321
|
-
repairRunningReceiptForSameRun?: boolean;
|
|
322
|
-
currentRunId: string;
|
|
323
|
-
receipt: WorkerRuntimeReceipt;
|
|
324
|
-
}): boolean {
|
|
325
|
-
return (
|
|
326
|
-
input.repairRunningReceiptForSameRun === true &&
|
|
327
|
-
input.receipt.status === 'running' &&
|
|
328
|
-
typeof input.receipt.runId === 'string' &&
|
|
329
|
-
input.receipt.runId.trim() === input.currentRunId
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
async function executeAndPersistReceipt<T>(input: {
|
|
334
|
-
key: string;
|
|
335
|
-
playName: string;
|
|
336
|
-
runId: string;
|
|
337
|
-
runAttempt?: number | null;
|
|
338
|
-
leaseId?: string | null;
|
|
339
|
-
wasFailed?: boolean;
|
|
340
|
-
execute: WorkerRuntimeReceiptExecute<T>;
|
|
341
|
-
receiptStore: WorkerRuntimeReceiptStore;
|
|
342
|
-
ownership: 'claimed' | 'reconciled';
|
|
343
|
-
budgetMeter?: WorkerWorkBudgetMeter;
|
|
344
|
-
heartbeatIntervalMs?: number;
|
|
345
|
-
}): Promise<T> {
|
|
346
|
-
let output: T;
|
|
347
|
-
try {
|
|
348
|
-
const leaseId = input.leaseId?.trim() || null;
|
|
349
|
-
output = await executeWithWorkerReceiptHeartbeats({
|
|
350
|
-
playName: input.playName,
|
|
351
|
-
runId: input.runId,
|
|
352
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
353
|
-
receiptStore: input.receiptStore,
|
|
354
|
-
budgetMeter: input.budgetMeter,
|
|
355
|
-
heartbeatIntervalMs: input.heartbeatIntervalMs,
|
|
356
|
-
targets: [{ key: input.key, leaseId }],
|
|
357
|
-
execute: () => input.execute({ leaseId }, input.wasFailed === true),
|
|
358
|
-
});
|
|
359
|
-
} catch (error) {
|
|
360
|
-
if (error instanceof RuntimeLeaseLostError) {
|
|
361
|
-
throw error;
|
|
362
|
-
}
|
|
363
|
-
if (
|
|
364
|
-
isPlayExecutionSuspendedError(error) ||
|
|
365
|
-
isPlayRowExecutionSuspendedError(error)
|
|
366
|
-
) {
|
|
367
|
-
if (!input.receiptStore.releaseReceipt) {
|
|
368
|
-
throw new Error(
|
|
369
|
-
`Runtime receipt ${input.key} suspended but the receipt store cannot release ownership: ${errorMessage(error)}`,
|
|
370
|
-
);
|
|
371
|
-
}
|
|
372
|
-
const released = await input.receiptStore.releaseReceipt({
|
|
373
|
-
playName: input.playName,
|
|
374
|
-
runId: input.runId,
|
|
375
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
376
|
-
key: input.key,
|
|
377
|
-
...(input.leaseId ? { leaseId: input.leaseId } : {}),
|
|
378
|
-
});
|
|
379
|
-
if (!released || released.status !== 'pending') {
|
|
380
|
-
throw new Error(
|
|
381
|
-
`Runtime receipt ${input.key} suspended but failed to release ownership: ${errorMessage(error)}`,
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
throw error;
|
|
385
|
-
}
|
|
386
|
-
const failed = await input.receiptStore.failReceipt({
|
|
387
|
-
playName: input.playName,
|
|
388
|
-
runId: input.runId,
|
|
389
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
390
|
-
key: input.key,
|
|
391
|
-
...(input.leaseId ? { leaseId: input.leaseId } : {}),
|
|
392
|
-
error: errorMessage(error),
|
|
393
|
-
failureKind: runtimeReceiptFailureKindForError(error),
|
|
394
|
-
});
|
|
395
|
-
if (!failed) {
|
|
396
|
-
throw new Error(
|
|
397
|
-
`Runtime receipt ${input.key} ${input.ownership} execution failed and failed receipt could not be persisted: ${errorMessage(error)}`,
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
throw error;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
const completed = await input.receiptStore.completeReceipt({
|
|
404
|
-
playName: input.playName,
|
|
405
|
-
runId: input.runId,
|
|
406
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
407
|
-
key: input.key,
|
|
408
|
-
...(input.leaseId ? { leaseId: input.leaseId } : {}),
|
|
409
|
-
output,
|
|
410
|
-
});
|
|
411
|
-
if (
|
|
412
|
-
!completed ||
|
|
413
|
-
(completed.status !== 'completed' && completed.status !== 'skipped')
|
|
414
|
-
) {
|
|
415
|
-
throw new Error(
|
|
416
|
-
`Runtime receipt ${input.key} lost receipt ownership before completion.`,
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
if (completed.output !== undefined) {
|
|
420
|
-
return receiptOutput<T>(completed);
|
|
421
|
-
}
|
|
422
|
-
return output;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
export async function runWorkerRuntimeReceiptBoundary<T>(
|
|
426
|
-
input: RuntimeReceiptContext & {
|
|
427
|
-
execute: WorkerRuntimeReceiptExecute<T>;
|
|
428
|
-
repairRunningReceiptForSameRun?: boolean;
|
|
429
|
-
repairRunningReceiptForSameRunAfterWaitTimeout?: boolean;
|
|
430
|
-
runningReceiptWaitMaxAttempts?: number;
|
|
431
|
-
runningReceiptWaitDelayMs?: number;
|
|
432
|
-
runtimeReceiptHeartbeatIntervalMs?: number;
|
|
433
|
-
runtimeReceiptLeaseTtlMs?: number;
|
|
434
|
-
reclaimRunning?: boolean;
|
|
435
|
-
forceFailedRefresh?: boolean;
|
|
436
|
-
},
|
|
437
|
-
): Promise<T> {
|
|
438
|
-
const key = scopedReceiptKey(input);
|
|
439
|
-
const receiptStore = input.receiptStore;
|
|
440
|
-
const claimed = await receiptStore.claimReceipt({
|
|
441
|
-
playName: input.playName,
|
|
442
|
-
runId: input.runId,
|
|
443
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
444
|
-
key,
|
|
445
|
-
leaseAware: true,
|
|
446
|
-
leaseTtlMs: input.runtimeReceiptLeaseTtlMs,
|
|
447
|
-
...(input.reclaimRunning === true ? { reclaimRunning: true } : {}),
|
|
448
|
-
...(input.forceFailedRefresh === true ? { forceFailedRefresh: true } : {}),
|
|
449
|
-
});
|
|
450
|
-
if (claimed.disposition === 'reused') {
|
|
451
|
-
return receiptOutput<T>(claimed.receipt);
|
|
452
|
-
}
|
|
453
|
-
if (
|
|
454
|
-
claimed.disposition === 'running' ||
|
|
455
|
-
claimed.disposition === 'blocked_active_lease'
|
|
456
|
-
) {
|
|
457
|
-
if (
|
|
458
|
-
shouldRepairSameRunRunningReceipt({
|
|
459
|
-
repairRunningReceiptForSameRun: input.repairRunningReceiptForSameRun,
|
|
460
|
-
currentRunId: input.runId,
|
|
461
|
-
receipt: claimed.receipt,
|
|
462
|
-
})
|
|
463
|
-
) {
|
|
464
|
-
const repaired = await receiptStore.claimReceipt({
|
|
465
|
-
playName: input.playName,
|
|
466
|
-
runId: input.runId,
|
|
467
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
468
|
-
key,
|
|
469
|
-
leaseAware: true,
|
|
470
|
-
leaseTtlMs: input.runtimeReceiptLeaseTtlMs,
|
|
471
|
-
reclaimRunning: true,
|
|
472
|
-
});
|
|
473
|
-
if (repaired.disposition === 'reused') {
|
|
474
|
-
return receiptOutput<T>(repaired.receipt);
|
|
475
|
-
}
|
|
476
|
-
if (repaired.disposition === 'failed') {
|
|
477
|
-
throw new Error(
|
|
478
|
-
`Runtime receipt ${key} is failed and could not be repaired: ${repaired.receipt.error ?? 'unknown error'}`,
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
if (repaired.disposition === 'claimed') {
|
|
482
|
-
return executeAndPersistReceipt({
|
|
483
|
-
key,
|
|
484
|
-
playName: input.playName,
|
|
485
|
-
runId: input.runId,
|
|
486
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
487
|
-
leaseId: repaired.receipt.leaseId ?? null,
|
|
488
|
-
execute: input.execute,
|
|
489
|
-
receiptStore,
|
|
490
|
-
ownership: 'claimed',
|
|
491
|
-
budgetMeter: input.budgetMeter,
|
|
492
|
-
heartbeatIntervalMs: input.runtimeReceiptHeartbeatIntervalMs,
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
try {
|
|
497
|
-
return await waitForReusableReceipt<T>({
|
|
498
|
-
key,
|
|
499
|
-
playName: input.playName,
|
|
500
|
-
receiptStore,
|
|
501
|
-
maxAttempts: input.runningReceiptWaitMaxAttempts,
|
|
502
|
-
delayMs: input.runningReceiptWaitDelayMs,
|
|
503
|
-
});
|
|
504
|
-
} catch (error) {
|
|
505
|
-
if (
|
|
506
|
-
input.repairRunningReceiptForSameRunAfterWaitTimeout === true &&
|
|
507
|
-
error instanceof RuntimeReceiptWaitTimeoutError &&
|
|
508
|
-
shouldRepairSameRunRunningReceipt({
|
|
509
|
-
repairRunningReceiptForSameRun: true,
|
|
510
|
-
currentRunId: input.runId,
|
|
511
|
-
receipt: claimed.receipt,
|
|
512
|
-
})
|
|
513
|
-
) {
|
|
514
|
-
const repaired = await receiptStore.claimReceipt({
|
|
515
|
-
playName: input.playName,
|
|
516
|
-
runId: input.runId,
|
|
517
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
518
|
-
key,
|
|
519
|
-
leaseAware: true,
|
|
520
|
-
leaseTtlMs: input.runtimeReceiptLeaseTtlMs,
|
|
521
|
-
reclaimRunning: true,
|
|
522
|
-
});
|
|
523
|
-
if (repaired.disposition === 'reused') {
|
|
524
|
-
return receiptOutput<T>(repaired.receipt);
|
|
525
|
-
}
|
|
526
|
-
if (repaired.disposition === 'failed') {
|
|
527
|
-
throw new Error(
|
|
528
|
-
`Runtime receipt ${key} is failed and could not be repaired after wait timeout: ${repaired.receipt.error ?? 'unknown error'}`,
|
|
529
|
-
);
|
|
530
|
-
}
|
|
531
|
-
if (repaired.disposition === 'claimed') {
|
|
532
|
-
return executeAndPersistReceipt({
|
|
533
|
-
key,
|
|
534
|
-
playName: input.playName,
|
|
535
|
-
runId: input.runId,
|
|
536
|
-
...(input.runAttempt != null
|
|
537
|
-
? { runAttempt: input.runAttempt }
|
|
538
|
-
: {}),
|
|
539
|
-
leaseId: repaired.receipt.leaseId ?? null,
|
|
540
|
-
execute: input.execute,
|
|
541
|
-
receiptStore,
|
|
542
|
-
ownership: 'claimed',
|
|
543
|
-
budgetMeter: input.budgetMeter,
|
|
544
|
-
heartbeatIntervalMs: input.runtimeReceiptHeartbeatIntervalMs,
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
throw error;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
if (claimed.disposition === 'failed') {
|
|
552
|
-
throw new Error(
|
|
553
|
-
`Runtime receipt ${key} is failed and could not be claimed: ${claimed.receipt.error ?? 'unknown error'}`,
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return executeAndPersistReceipt({
|
|
558
|
-
key,
|
|
559
|
-
playName: input.playName,
|
|
560
|
-
runId: input.runId,
|
|
561
|
-
...(input.runAttempt != null ? { runAttempt: input.runAttempt } : {}),
|
|
562
|
-
leaseId: claimed.receipt.leaseId ?? null,
|
|
563
|
-
wasFailed: claimed.wasFailed === true,
|
|
564
|
-
execute: input.execute,
|
|
565
|
-
receiptStore,
|
|
566
|
-
ownership: 'claimed',
|
|
567
|
-
budgetMeter: input.budgetMeter,
|
|
568
|
-
heartbeatIntervalMs: input.runtimeReceiptHeartbeatIntervalMs,
|
|
569
|
-
});
|
|
570
|
-
}
|
package/dist/bundling-sources/apps/play-runner-workers/src/runtime/result-dataset-persistence.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { augmentSheetContractWithDatasetFields } from '../../../../shared_libs/play-data-plane/sheet-contract';
|
|
2
|
-
import type { PlaySheetContract } from '../../../../shared_libs/plays/static-pipeline';
|
|
3
|
-
import type { OutputDatasetRow } from './output-datasets';
|
|
4
|
-
|
|
5
|
-
export type StableResultDatasetPersistenceContract = {
|
|
6
|
-
sheetContract: PlaySheetContract;
|
|
7
|
-
cachedChunks: OutputDatasetRow[][] | null;
|
|
8
|
-
rowCount: number;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export async function collectStableResultDatasetPersistenceContract(input: {
|
|
12
|
-
contract: PlaySheetContract;
|
|
13
|
-
chunks:
|
|
14
|
-
| AsyncIterable<readonly OutputDatasetRow[]>
|
|
15
|
-
| Iterable<readonly OutputDatasetRow[]>;
|
|
16
|
-
cacheChunks?: boolean;
|
|
17
|
-
}): Promise<StableResultDatasetPersistenceContract> {
|
|
18
|
-
const fields = new Set<string>();
|
|
19
|
-
const cachedChunks: OutputDatasetRow[][] | null = input.cacheChunks
|
|
20
|
-
? []
|
|
21
|
-
: null;
|
|
22
|
-
let rowCount = 0;
|
|
23
|
-
|
|
24
|
-
for await (const chunk of input.chunks) {
|
|
25
|
-
if (chunk.length === 0) continue;
|
|
26
|
-
rowCount += chunk.length;
|
|
27
|
-
for (const row of chunk) {
|
|
28
|
-
for (const field of Object.keys(row)) {
|
|
29
|
-
fields.add(field);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (cachedChunks) {
|
|
33
|
-
cachedChunks.push(chunk.map((row) => ({ ...row })));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const unionRow =
|
|
38
|
-
fields.size === 0
|
|
39
|
-
? []
|
|
40
|
-
: [Object.fromEntries([...fields].map((field) => [field, null]))];
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
sheetContract: augmentSheetContractWithDatasetFields({
|
|
44
|
-
contract: input.contract,
|
|
45
|
-
rows: unionRow,
|
|
46
|
-
}),
|
|
47
|
-
cachedChunks,
|
|
48
|
-
rowCount,
|
|
49
|
-
};
|
|
50
|
-
}
|