deepline 0.1.22 → 0.1.24
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/cli/index.js +540 -56
- package/dist/cli/index.mjs +540 -56
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +30 -3
- package/dist/index.mjs +30 -3
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +97 -81
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +18 -5
- package/dist/repo/apps/play-runner-workers/src/entry.ts +43 -32
- package/dist/repo/apps/play-runner-workers/src/runtime/live-progress.ts +18 -0
- package/dist/repo/sdk/src/client.ts +38 -4
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -0
- package/dist/repo/sdk/src/version.ts +1 -1
- package/dist/repo/shared_libs/play-runtime/execution-plan.ts +27 -2
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -241,7 +241,7 @@ function resolveConfig(options) {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
// src/version.ts
|
|
244
|
-
var SDK_VERSION = "0.1.
|
|
244
|
+
var SDK_VERSION = "0.1.24";
|
|
245
245
|
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
246
246
|
|
|
247
247
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -529,6 +529,19 @@ function sleep(ms) {
|
|
|
529
529
|
// src/client.ts
|
|
530
530
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
531
531
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
532
|
+
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
533
|
+
function sleep2(ms) {
|
|
534
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
535
|
+
}
|
|
536
|
+
function isTransientCompileManifestError(error) {
|
|
537
|
+
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
538
|
+
return error.statusCode === 408 || error.statusCode === 425 || error.statusCode === 499 || error.statusCode >= 500 && error.statusCode < 600;
|
|
539
|
+
}
|
|
540
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
541
|
+
return /fetch failed|connection (?:closed|reset|terminated)|socket hang up|econnreset|etimedout|eai_again|abort/i.test(
|
|
542
|
+
message
|
|
543
|
+
);
|
|
544
|
+
}
|
|
532
545
|
function isRecord(value) {
|
|
533
546
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
534
547
|
}
|
|
@@ -934,8 +947,22 @@ var DeeplineClient = class {
|
|
|
934
947
|
});
|
|
935
948
|
}
|
|
936
949
|
async compilePlayManifest(input) {
|
|
937
|
-
const
|
|
938
|
-
|
|
950
|
+
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
951
|
+
0,
|
|
952
|
+
Math.max(0, this.config.maxRetries)
|
|
953
|
+
);
|
|
954
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
955
|
+
try {
|
|
956
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input);
|
|
957
|
+
return response.compilerManifest;
|
|
958
|
+
} catch (error) {
|
|
959
|
+
const delayMs = retryDelays[attempt];
|
|
960
|
+
if (delayMs === void 0 || !isTransientCompileManifestError(error)) {
|
|
961
|
+
throw error;
|
|
962
|
+
}
|
|
963
|
+
await sleep2(delayMs);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
939
966
|
}
|
|
940
967
|
/**
|
|
941
968
|
* Check a bundled play artifact against the server's current play compiler.
|
package/dist/index.mjs
CHANGED
|
@@ -195,7 +195,7 @@ function resolveConfig(options) {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
// src/version.ts
|
|
198
|
-
var SDK_VERSION = "0.1.
|
|
198
|
+
var SDK_VERSION = "0.1.24";
|
|
199
199
|
var SDK_API_CONTRACT = "2026-05-runs-v2";
|
|
200
200
|
|
|
201
201
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
@@ -483,6 +483,19 @@ function sleep(ms) {
|
|
|
483
483
|
// src/client.ts
|
|
484
484
|
var TERMINAL_PLAY_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
485
485
|
var INCLUDE_TOOL_METADATA_HEADER = "x-deepline-include-tool-metadata";
|
|
486
|
+
var COMPILE_MANIFEST_RETRY_DELAYS_MS = [250, 1e3];
|
|
487
|
+
function sleep2(ms) {
|
|
488
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
489
|
+
}
|
|
490
|
+
function isTransientCompileManifestError(error) {
|
|
491
|
+
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
492
|
+
return error.statusCode === 408 || error.statusCode === 425 || error.statusCode === 499 || error.statusCode >= 500 && error.statusCode < 600;
|
|
493
|
+
}
|
|
494
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
495
|
+
return /fetch failed|connection (?:closed|reset|terminated)|socket hang up|econnreset|etimedout|eai_again|abort/i.test(
|
|
496
|
+
message
|
|
497
|
+
);
|
|
498
|
+
}
|
|
486
499
|
function isRecord(value) {
|
|
487
500
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
488
501
|
}
|
|
@@ -888,8 +901,22 @@ var DeeplineClient = class {
|
|
|
888
901
|
});
|
|
889
902
|
}
|
|
890
903
|
async compilePlayManifest(input) {
|
|
891
|
-
const
|
|
892
|
-
|
|
904
|
+
const retryDelays = COMPILE_MANIFEST_RETRY_DELAYS_MS.slice(
|
|
905
|
+
0,
|
|
906
|
+
Math.max(0, this.config.maxRetries)
|
|
907
|
+
);
|
|
908
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
909
|
+
try {
|
|
910
|
+
const response = await this.http.post("/api/v2/plays/compile-manifest", input);
|
|
911
|
+
return response.compilerManifest;
|
|
912
|
+
} catch (error) {
|
|
913
|
+
const delayMs = retryDelays[attempt];
|
|
914
|
+
if (delayMs === void 0 || !isTransientCompileManifestError(error)) {
|
|
915
|
+
throw error;
|
|
916
|
+
}
|
|
917
|
+
await sleep2(delayMs);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
893
920
|
}
|
|
894
921
|
/**
|
|
895
922
|
* Check a bundled play artifact against the server's current play compiler.
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
COORDINATOR_INTERNAL_TOKEN_HEADER,
|
|
34
34
|
COORDINATOR_RUN_SCOPE_HEADER,
|
|
35
35
|
} from '../../../shared_libs/play-runtime/coordinator-headers';
|
|
36
|
+
import { sanitizeLiveLogLines } from './runtime/live-progress';
|
|
36
37
|
|
|
37
38
|
export { DynamicWorkflowBinding };
|
|
38
39
|
|
|
@@ -125,6 +126,8 @@ type CoordinatorTerminalState = {
|
|
|
125
126
|
totalRows?: unknown;
|
|
126
127
|
durationMs?: unknown;
|
|
127
128
|
playName?: string | null;
|
|
129
|
+
liveLogs?: string[] | null;
|
|
130
|
+
liveNodeProgress?: unknown;
|
|
128
131
|
completedAt?: number;
|
|
129
132
|
};
|
|
130
133
|
|
|
@@ -154,6 +157,7 @@ type CoordinatorRunEvent =
|
|
|
154
157
|
activeNodeId?: string | null;
|
|
155
158
|
activeArtifactTableNamespace?: string | null;
|
|
156
159
|
updatedAt?: number | null;
|
|
160
|
+
liveNodeProgress?: unknown;
|
|
157
161
|
}
|
|
158
162
|
| {
|
|
159
163
|
seq?: number;
|
|
@@ -166,6 +170,8 @@ type CoordinatorRunEvent =
|
|
|
166
170
|
totalRows?: unknown;
|
|
167
171
|
durationMs?: unknown;
|
|
168
172
|
playName?: string | null;
|
|
173
|
+
liveLogs?: string[] | null;
|
|
174
|
+
liveNodeProgress?: unknown;
|
|
169
175
|
};
|
|
170
176
|
|
|
171
177
|
type InlineWorkerRunResponse = {
|
|
@@ -229,12 +235,7 @@ interface CoordinatorEnv {
|
|
|
229
235
|
HARNESS?: import('../../play-harness-worker/src/rpc-types').PlayHarnessRpc;
|
|
230
236
|
}
|
|
231
237
|
|
|
232
|
-
const WORKFLOW_READ_ONLY_ACTIONS = new Set([
|
|
233
|
-
'',
|
|
234
|
-
'result',
|
|
235
|
-
'status',
|
|
236
|
-
'tail',
|
|
237
|
-
]);
|
|
238
|
+
const WORKFLOW_READ_ONLY_ACTIONS = new Set(['', 'result', 'status', 'tail']);
|
|
238
239
|
|
|
239
240
|
function authorizeCoordinatorControlRequest(input: {
|
|
240
241
|
request: Request;
|
|
@@ -411,11 +412,14 @@ async function appendCoordinatorRunEvent(
|
|
|
411
412
|
event: CoordinatorRunEvent,
|
|
412
413
|
): Promise<void> {
|
|
413
414
|
const stub = env.PLAY_DEDUP.get(env.PLAY_DEDUP.idFromName(event.runId));
|
|
414
|
-
const response = await stub.fetch(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
415
|
+
const response = await stub.fetch(
|
|
416
|
+
'https://deepline.dedup.internal/event-add',
|
|
417
|
+
{
|
|
418
|
+
method: 'POST',
|
|
419
|
+
headers: { 'content-type': 'application/json' },
|
|
420
|
+
body: JSON.stringify(event),
|
|
421
|
+
},
|
|
422
|
+
);
|
|
419
423
|
if (!response.ok) {
|
|
420
424
|
throw new Error(`coordinator event append failed ${response.status}`);
|
|
421
425
|
}
|
|
@@ -455,7 +459,8 @@ async function listCoordinatorRunEvents(input: {
|
|
|
455
459
|
typeof event.ts === 'number',
|
|
456
460
|
)
|
|
457
461
|
: [],
|
|
458
|
-
latestSeq:
|
|
462
|
+
latestSeq:
|
|
463
|
+
typeof body.latestSeq === 'number' ? body.latestSeq : input.afterSeq,
|
|
459
464
|
};
|
|
460
465
|
}
|
|
461
466
|
|
|
@@ -546,7 +551,9 @@ function buildDynamicWorkflowMetadata(
|
|
|
546
551
|
};
|
|
547
552
|
}
|
|
548
553
|
|
|
549
|
-
function buildDispatcherEnvelope(
|
|
554
|
+
function buildDispatcherEnvelope(
|
|
555
|
+
params: PlayWorkflowParams,
|
|
556
|
+
): DispatcherEnvelope {
|
|
550
557
|
// Mirrors @cloudflare/dynamic-workflows' envelope. We need to send the
|
|
551
558
|
// dispatcher payload via Workflow sendEvent for prewarmed instances; the
|
|
552
559
|
// public wrapper only applies this envelope to create() params.
|
|
@@ -739,7 +746,9 @@ type WorkflowPoolListEntry = {
|
|
|
739
746
|
expiresAt: number;
|
|
740
747
|
};
|
|
741
748
|
|
|
742
|
-
async function workflowPoolCount(
|
|
749
|
+
async function workflowPoolCount(
|
|
750
|
+
env: CoordinatorEnv,
|
|
751
|
+
): Promise<WorkflowPoolCounts> {
|
|
743
752
|
const body = await callWorkflowPool<{
|
|
744
753
|
available?: unknown;
|
|
745
754
|
warming?: unknown;
|
|
@@ -810,17 +819,13 @@ async function markWorkflowPoolIdReady(
|
|
|
810
819
|
env: CoordinatorEnv,
|
|
811
820
|
poolId: string,
|
|
812
821
|
): Promise<boolean> {
|
|
813
|
-
const body = await callWorkflowPool<{ ready?: unknown }>(
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
version: WORKFLOW_POOL_PROTOCOL_VERSION,
|
|
821
|
-
}),
|
|
822
|
-
},
|
|
823
|
-
);
|
|
822
|
+
const body = await callWorkflowPool<{ ready?: unknown }>(env, '/pool-ready', {
|
|
823
|
+
method: 'POST',
|
|
824
|
+
body: JSON.stringify({
|
|
825
|
+
poolId,
|
|
826
|
+
version: WORKFLOW_POOL_PROTOCOL_VERSION,
|
|
827
|
+
}),
|
|
828
|
+
});
|
|
824
829
|
return body.ready === true;
|
|
825
830
|
}
|
|
826
831
|
|
|
@@ -948,7 +953,9 @@ async function waitForWorkflowPoolReadySignal(input: {
|
|
|
948
953
|
polls += 1;
|
|
949
954
|
const [entry, status] = await Promise.all([
|
|
950
955
|
listWorkflowPoolEntries(input.env)
|
|
951
|
-
.then((entries) =>
|
|
956
|
+
.then((entries) =>
|
|
957
|
+
entries.find((candidate) => candidate.id === input.poolId),
|
|
958
|
+
)
|
|
952
959
|
.catch(() => undefined),
|
|
953
960
|
input.instance.status().catch(() => null),
|
|
954
961
|
]);
|
|
@@ -1206,7 +1213,8 @@ async function submitViaPooledWorkflow(input: {
|
|
|
1206
1213
|
if (!pooledInstanceId) {
|
|
1207
1214
|
// A pool miss must not block the user path. Refilling is handled by the
|
|
1208
1215
|
// caller's waitUntil after submit, so fall through to cold create now.
|
|
1209
|
-
const counts =
|
|
1216
|
+
const counts =
|
|
1217
|
+
missCounts ?? (await workflowPoolCount(input.env).catch(() => null));
|
|
1210
1218
|
input.recordSubmitTiming({
|
|
1211
1219
|
phase: 'coordinator.workflow_pool_refill_on_miss',
|
|
1212
1220
|
ms: 0,
|
|
@@ -1404,7 +1412,9 @@ async function mintChildWorkflowExecutorToken(input: {
|
|
|
1404
1412
|
}
|
|
1405
1413
|
const executorToken = parsed.executorToken;
|
|
1406
1414
|
if (typeof executorToken !== 'string' || !executorToken.trim()) {
|
|
1407
|
-
throw new Error(
|
|
1415
|
+
throw new Error(
|
|
1416
|
+
'Origin child executor token response was missing executorToken.',
|
|
1417
|
+
);
|
|
1408
1418
|
}
|
|
1409
1419
|
return executorToken;
|
|
1410
1420
|
}
|
|
@@ -1447,10 +1457,15 @@ function normalizeRuntimeBaseUrl(value: unknown): string | null {
|
|
|
1447
1457
|
return parsed.toString().replace(/\/$/, '');
|
|
1448
1458
|
}
|
|
1449
1459
|
|
|
1450
|
-
function resolveRuntimeBaseUrl(
|
|
1451
|
-
|
|
1460
|
+
function resolveRuntimeBaseUrl(
|
|
1461
|
+
env: CoordinatorEnv,
|
|
1462
|
+
body: Record<string, unknown>,
|
|
1463
|
+
): string {
|
|
1464
|
+
return (
|
|
1465
|
+
normalizeRuntimeBaseUrl(body.callbackBaseUrl) ??
|
|
1452
1466
|
normalizeRuntimeBaseUrl(body.baseUrl) ??
|
|
1453
|
-
env.DEEPLINE_API_BASE_URL.replace(/\/$/, '')
|
|
1467
|
+
env.DEEPLINE_API_BASE_URL.replace(/\/$/, '')
|
|
1468
|
+
);
|
|
1454
1469
|
}
|
|
1455
1470
|
|
|
1456
1471
|
function validateChildSubmitBody(input: {
|
|
@@ -1603,7 +1618,9 @@ function buildChildWorkflowParams(input: {
|
|
|
1603
1618
|
};
|
|
1604
1619
|
}
|
|
1605
1620
|
|
|
1606
|
-
function runRequestFromPlayWorkflowParams(
|
|
1621
|
+
function runRequestFromPlayWorkflowParams(
|
|
1622
|
+
params: PlayWorkflowParams,
|
|
1623
|
+
): Record<string, unknown> {
|
|
1607
1624
|
return {
|
|
1608
1625
|
runId: params.runId,
|
|
1609
1626
|
callbackUrl: params.baseUrl,
|
|
@@ -1616,7 +1633,8 @@ function runRequestFromPlayWorkflowParams(params: PlayWorkflowParams): Record<st
|
|
|
1616
1633
|
runtimeInput: params.input,
|
|
1617
1634
|
inlineCsv: params.inlineCsv ?? null,
|
|
1618
1635
|
inputR2Keys:
|
|
1619
|
-
params.inputFile?.r2Key &&
|
|
1636
|
+
params.inputFile?.r2Key &&
|
|
1637
|
+
(params.inputFile.name || params.inputFile.path)
|
|
1620
1638
|
? {
|
|
1621
1639
|
[String(params.inputFile.name ?? params.inputFile.path)]:
|
|
1622
1640
|
params.inputFile.r2Key,
|
|
@@ -1720,13 +1738,8 @@ async function executeChildInline(input: {
|
|
|
1720
1738
|
if (!validated.ok) {
|
|
1721
1739
|
throw new Error(String(validated.error.message ?? 'Invalid child submit.'));
|
|
1722
1740
|
}
|
|
1723
|
-
const {
|
|
1724
|
-
|
|
1725
|
-
governance,
|
|
1726
|
-
childPlayName,
|
|
1727
|
-
orgId,
|
|
1728
|
-
parentExecutorToken,
|
|
1729
|
-
} = validated;
|
|
1741
|
+
const { manifest, governance, childPlayName, orgId, parentExecutorToken } =
|
|
1742
|
+
validated;
|
|
1730
1743
|
const childRunId = buildChildRunId(childPlayName);
|
|
1731
1744
|
const timings: CoordinatorTiming[] = [];
|
|
1732
1745
|
const trace = (
|
|
@@ -1801,9 +1814,7 @@ async function executeChildInline(input: {
|
|
|
1801
1814
|
artifactStorageKey: manifest.artifactStorageKey,
|
|
1802
1815
|
artifactHash: manifest.artifactHash,
|
|
1803
1816
|
dynamicWorkerCode:
|
|
1804
|
-
typeof manifest.bundledCode === 'string'
|
|
1805
|
-
? manifest.bundledCode
|
|
1806
|
-
: null,
|
|
1817
|
+
typeof manifest.bundledCode === 'string' ? manifest.bundledCode : null,
|
|
1807
1818
|
packagedFiles: null,
|
|
1808
1819
|
});
|
|
1809
1820
|
trace('coordinator.inline_child_loader_get', loaderStartedAt);
|
|
@@ -2027,9 +2038,7 @@ export class RuntimeApi extends WorkerEntrypoint<CoordinatorEnv, undefined> {
|
|
|
2027
2038
|
type: 'progress',
|
|
2028
2039
|
status,
|
|
2029
2040
|
ts: Date.now(),
|
|
2030
|
-
logs:
|
|
2031
|
-
? body.liveLogs.filter((line): line is string => typeof line === 'string')
|
|
2032
|
-
: undefined,
|
|
2041
|
+
logs: sanitizeLiveLogLines(body.liveLogs) ?? undefined,
|
|
2033
2042
|
activeNodeId:
|
|
2034
2043
|
typeof body.activeNodeId === 'string' ? body.activeNodeId : null,
|
|
2035
2044
|
activeArtifactTableNamespace:
|
|
@@ -2040,6 +2049,8 @@ export class RuntimeApi extends WorkerEntrypoint<CoordinatorEnv, undefined> {
|
|
|
2040
2049
|
typeof body.lastCheckpointAt === 'number'
|
|
2041
2050
|
? body.lastCheckpointAt
|
|
2042
2051
|
: null,
|
|
2052
|
+
liveNodeProgress:
|
|
2053
|
+
body.liveNodeProgress !== undefined ? body.liveNodeProgress : undefined,
|
|
2043
2054
|
});
|
|
2044
2055
|
}
|
|
2045
2056
|
}
|
|
@@ -2110,7 +2121,10 @@ export class CoordinatorControl extends WorkerEntrypoint<
|
|
|
2110
2121
|
await appendCoordinatorPerfTrace(this.env, payload);
|
|
2111
2122
|
}
|
|
2112
2123
|
|
|
2113
|
-
async recordRunEvent(
|
|
2124
|
+
async recordRunEvent(
|
|
2125
|
+
runId: string,
|
|
2126
|
+
event: CoordinatorRunEvent,
|
|
2127
|
+
): Promise<void> {
|
|
2114
2128
|
if (!runId || event.runId !== runId) {
|
|
2115
2129
|
throw new Error('Run event runId mismatch.');
|
|
2116
2130
|
}
|
|
@@ -2280,9 +2294,9 @@ export class DynamicWorkflow extends WorkflowEntrypoint<
|
|
|
2280
2294
|
totalRows: output?.totalRows ?? output?.outputRows ?? null,
|
|
2281
2295
|
durationMs: output?.durationMs ?? null,
|
|
2282
2296
|
playName:
|
|
2283
|
-
typeof output?.playName === 'string'
|
|
2284
|
-
|
|
2285
|
-
|
|
2297
|
+
typeof output?.playName === 'string' ? output.playName : null,
|
|
2298
|
+
liveLogs: sanitizeLiveLogLines(output?.liveLogs),
|
|
2299
|
+
liveNodeProgress: output?.liveNodeProgress ?? null,
|
|
2286
2300
|
});
|
|
2287
2301
|
trace({
|
|
2288
2302
|
runId: runIdForTrace,
|
|
@@ -2407,8 +2421,12 @@ const coordinatorEntrypoint = {
|
|
|
2407
2421
|
return new Response('unauthorized', { status: 401 });
|
|
2408
2422
|
}
|
|
2409
2423
|
const startedAt = Date.now();
|
|
2410
|
-
const minAvailableRaw = Number(
|
|
2411
|
-
|
|
2424
|
+
const minAvailableRaw = Number(
|
|
2425
|
+
url.searchParams.get('minAvailable') ?? '',
|
|
2426
|
+
);
|
|
2427
|
+
const waitTimeoutMsRaw = Number(
|
|
2428
|
+
url.searchParams.get('waitTimeoutMs') ?? '',
|
|
2429
|
+
);
|
|
2412
2430
|
const result = await refillWorkflowPool(env, {
|
|
2413
2431
|
waitReady: url.searchParams.get('waitReady') === '1',
|
|
2414
2432
|
minAvailable:
|
|
@@ -3017,6 +3035,9 @@ async function handleWorkflowRoute(input: {
|
|
|
3017
3035
|
error: terminalEvent.error ?? null,
|
|
3018
3036
|
totalRows: terminalEvent.totalRows ?? null,
|
|
3019
3037
|
durationMs: terminalEvent.durationMs ?? null,
|
|
3038
|
+
completedAt: terminalEvent.ts,
|
|
3039
|
+
liveLogs: sanitizeLiveLogLines(terminalEvent.liveLogs),
|
|
3040
|
+
liveNodeProgress: terminalEvent.liveNodeProgress ?? null,
|
|
3020
3041
|
events: eventResult?.events ?? [],
|
|
3021
3042
|
latestSeq: eventResult?.latestSeq ?? afterSeq,
|
|
3022
3043
|
wait: null,
|
|
@@ -3039,8 +3060,7 @@ async function handleWorkflowRoute(input: {
|
|
|
3039
3060
|
coordinatorObserve: {
|
|
3040
3061
|
ms: Date.now() - statusStartedAt,
|
|
3041
3062
|
waitMs,
|
|
3042
|
-
workflowStatus:
|
|
3043
|
-
eventResult?.events.length ? 'event' : 'event-timeout',
|
|
3063
|
+
workflowStatus: eventResult?.events.length ? 'event' : 'event-timeout',
|
|
3044
3064
|
statusPolls: 0,
|
|
3045
3065
|
instanceId: null,
|
|
3046
3066
|
},
|
|
@@ -3126,27 +3146,31 @@ async function handleWorkflowRoute(input: {
|
|
|
3126
3146
|
status: mapWorkflowStatus(await instance.status()),
|
|
3127
3147
|
});
|
|
3128
3148
|
}
|
|
3129
|
-
if (
|
|
3130
|
-
action === 'result' || action === 'status' || action === ''
|
|
3131
|
-
) {
|
|
3149
|
+
if (action === 'result' || action === 'status' || action === '') {
|
|
3132
3150
|
const includeTrace =
|
|
3133
3151
|
new URL(request.url).searchParams.get('trace') === '1';
|
|
3134
3152
|
const statusStartedAt = Date.now();
|
|
3135
|
-
const terminalState = await readCoordinatorTerminalState(
|
|
3136
|
-
|
|
3137
|
-
|
|
3153
|
+
const terminalState = await readCoordinatorTerminalState(
|
|
3154
|
+
env,
|
|
3155
|
+
runId,
|
|
3156
|
+
).catch(() => null);
|
|
3138
3157
|
if (terminalState) {
|
|
3139
3158
|
const coordinatorTrace = includeTrace
|
|
3140
3159
|
? await listCoordinatorPerfTrace(env, runId).catch(() => [])
|
|
3141
3160
|
: [];
|
|
3142
3161
|
return Response.json({
|
|
3143
3162
|
runId,
|
|
3144
|
-
...(terminalState.playName
|
|
3163
|
+
...(terminalState.playName
|
|
3164
|
+
? { playName: terminalState.playName }
|
|
3165
|
+
: {}),
|
|
3145
3166
|
status: terminalState.status,
|
|
3146
3167
|
result: terminalState.result ?? null,
|
|
3147
3168
|
error: terminalState.error ?? null,
|
|
3148
3169
|
totalRows: terminalState.totalRows ?? null,
|
|
3149
3170
|
durationMs: terminalState.durationMs ?? null,
|
|
3171
|
+
completedAt: terminalState.completedAt ?? null,
|
|
3172
|
+
liveLogs: sanitizeLiveLogLines(terminalState.liveLogs),
|
|
3173
|
+
liveNodeProgress: terminalState.liveNodeProgress ?? null,
|
|
3150
3174
|
wait: null,
|
|
3151
3175
|
coordinatorObserve: {
|
|
3152
3176
|
ms: Date.now() - statusStartedAt,
|
|
@@ -3228,8 +3252,7 @@ function stableHash(value: string): string {
|
|
|
3228
3252
|
return (hash >>> 0).toString(36);
|
|
3229
3253
|
}
|
|
3230
3254
|
|
|
3231
|
-
const DYNAMIC_PLAY_WORKER_HARNESS_VERSION =
|
|
3232
|
-
'h6-runtime-api-coordinator-deploy-scoped';
|
|
3255
|
+
const DYNAMIC_PLAY_WORKER_HARNESS_VERSION = 'h7-skip-high-volume-tool-traces';
|
|
3233
3256
|
const DYNAMIC_WORKER_BUNDLED_CODE_CACHE_MAX_ENTRIES = 64;
|
|
3234
3257
|
const dynamicWorkerBundledCodeCache = new Map<string, string>();
|
|
3235
3258
|
|
|
@@ -3614,8 +3637,7 @@ async function handleStagedFilePut(
|
|
|
3614
3637
|
if (rawKey) {
|
|
3615
3638
|
const key = rawKey;
|
|
3616
3639
|
const contentType =
|
|
3617
|
-
url.searchParams.get('contentType')?.trim() ||
|
|
3618
|
-
'application/octet-stream';
|
|
3640
|
+
url.searchParams.get('contentType')?.trim() || 'application/octet-stream';
|
|
3619
3641
|
const expectedBytes = Number(url.searchParams.get('bytes') ?? 'NaN');
|
|
3620
3642
|
if (!isAllowedStagedFileStorageKey(key)) {
|
|
3621
3643
|
return Response.json(
|
|
@@ -3674,14 +3696,12 @@ async function handleStagedFilePut(
|
|
|
3674
3696
|
timingsMs: { read: readMs, put: putMs },
|
|
3675
3697
|
});
|
|
3676
3698
|
}
|
|
3677
|
-
const body = (await request.json().catch(() => null)) as
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
}
|
|
3684
|
-
| null;
|
|
3699
|
+
const body = (await request.json().catch(() => null)) as {
|
|
3700
|
+
key?: unknown;
|
|
3701
|
+
contentBase64?: unknown;
|
|
3702
|
+
contentType?: unknown;
|
|
3703
|
+
bytes?: unknown;
|
|
3704
|
+
} | null;
|
|
3685
3705
|
const key = typeof body?.key === 'string' ? body.key.trim() : '';
|
|
3686
3706
|
const contentBase64 =
|
|
3687
3707
|
typeof body?.contentBase64 === 'string' ? body.contentBase64 : '';
|
|
@@ -3691,10 +3711,7 @@ async function handleStagedFilePut(
|
|
|
3691
3711
|
: 'application/octet-stream';
|
|
3692
3712
|
const expectedBytes = typeof body?.bytes === 'number' ? body.bytes : NaN;
|
|
3693
3713
|
if (!isAllowedStagedFileStorageKey(key)) {
|
|
3694
|
-
return Response.json(
|
|
3695
|
-
{ error: 'invalid staged file key' },
|
|
3696
|
-
{ status: 400 },
|
|
3697
|
-
);
|
|
3714
|
+
return Response.json({ error: 'invalid staged file key' }, { status: 400 });
|
|
3698
3715
|
}
|
|
3699
3716
|
if (
|
|
3700
3717
|
!contentBase64 ||
|
|
@@ -4003,10 +4020,7 @@ function makeCoordinatorControlBinding():
|
|
|
4003
4020
|
runId: string,
|
|
4004
4021
|
payload: CoordinatorPerfTracePayload,
|
|
4005
4022
|
): Promise<void>;
|
|
4006
|
-
recordRunEvent(
|
|
4007
|
-
runId: string,
|
|
4008
|
-
event: CoordinatorRunEvent,
|
|
4009
|
-
): Promise<void>;
|
|
4023
|
+
recordRunEvent(runId: string, event: CoordinatorRunEvent): Promise<void>;
|
|
4010
4024
|
};
|
|
4011
4025
|
};
|
|
4012
4026
|
const ctor = exports.CoordinatorControl;
|
|
@@ -4064,6 +4078,8 @@ function mapWorkflowResult(
|
|
|
4064
4078
|
error,
|
|
4065
4079
|
totalRows: output?.totalRows ?? output?.outputRows ?? null,
|
|
4066
4080
|
durationMs: output?.durationMs ?? null,
|
|
4081
|
+
liveLogs: sanitizeLiveLogLines(output?.liveLogs),
|
|
4082
|
+
liveNodeProgress: output?.liveNodeProgress ?? null,
|
|
4067
4083
|
wait:
|
|
4068
4084
|
mapped === 'sleeping'
|
|
4069
4085
|
? {
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
* Latency: ~5ms per request (DO storage is sub-ms; HTTP add ~3-5ms).
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { sanitizeLiveLogLines } from './runtime/live-progress';
|
|
20
|
+
|
|
19
21
|
type DedupEntry =
|
|
20
22
|
| { status: 'in_flight'; claimedBy: string; claimedAt: number }
|
|
21
23
|
| { status: 'completed'; result: unknown; completedAt: number }
|
|
@@ -91,6 +93,8 @@ type CoordinatorTerminalState = {
|
|
|
91
93
|
totalRows?: unknown;
|
|
92
94
|
durationMs?: unknown;
|
|
93
95
|
playName?: string | null;
|
|
96
|
+
liveLogs?: string[] | null;
|
|
97
|
+
liveNodeProgress?: unknown;
|
|
94
98
|
completedAt: number;
|
|
95
99
|
};
|
|
96
100
|
|
|
@@ -120,6 +124,7 @@ type CoordinatorRunEvent =
|
|
|
120
124
|
activeNodeId?: string | null;
|
|
121
125
|
activeArtifactTableNamespace?: string | null;
|
|
122
126
|
updatedAt?: number | null;
|
|
127
|
+
liveNodeProgress?: unknown;
|
|
123
128
|
}
|
|
124
129
|
| {
|
|
125
130
|
seq: number;
|
|
@@ -132,6 +137,8 @@ type CoordinatorRunEvent =
|
|
|
132
137
|
totalRows?: unknown;
|
|
133
138
|
durationMs?: unknown;
|
|
134
139
|
playName?: string | null;
|
|
140
|
+
liveLogs?: string[] | null;
|
|
141
|
+
liveNodeProgress?: unknown;
|
|
135
142
|
};
|
|
136
143
|
|
|
137
144
|
type OmitRunEventSequence<T> = T extends unknown ? Omit<T, 'seq'> : never;
|
|
@@ -851,7 +858,8 @@ export class PlayDedup implements DurableObject {
|
|
|
851
858
|
state: startedAt !== null ? 'started' : 'claimed',
|
|
852
859
|
blockedInstanceId: null,
|
|
853
860
|
claimedAt:
|
|
854
|
-
existing?.version === version &&
|
|
861
|
+
existing?.version === version &&
|
|
862
|
+
typeof existing.claimedAt === 'number'
|
|
855
863
|
? existing.claimedAt
|
|
856
864
|
: now,
|
|
857
865
|
startedAt,
|
|
@@ -904,7 +912,8 @@ export class PlayDedup implements DurableObject {
|
|
|
904
912
|
state: 'blocked',
|
|
905
913
|
blockedInstanceId: instanceId,
|
|
906
914
|
claimedAt:
|
|
907
|
-
existing?.version === version &&
|
|
915
|
+
existing?.version === version &&
|
|
916
|
+
typeof existing.claimedAt === 'number'
|
|
908
917
|
? existing.claimedAt
|
|
909
918
|
: now,
|
|
910
919
|
startedAt: null,
|
|
@@ -1056,6 +1065,8 @@ export class PlayDedup implements DurableObject {
|
|
|
1056
1065
|
totalRows: body.totalRows,
|
|
1057
1066
|
durationMs: body.durationMs,
|
|
1058
1067
|
playName: typeof body.playName === 'string' ? body.playName : null,
|
|
1068
|
+
liveLogs: sanitizeLiveLogLines(body.liveLogs),
|
|
1069
|
+
liveNodeProgress: body.liveNodeProgress,
|
|
1059
1070
|
completedAt:
|
|
1060
1071
|
typeof body.completedAt === 'number' ? body.completedAt : Date.now(),
|
|
1061
1072
|
};
|
|
@@ -1069,6 +1080,8 @@ export class PlayDedup implements DurableObject {
|
|
|
1069
1080
|
totalRows: state.totalRows,
|
|
1070
1081
|
durationMs: state.durationMs,
|
|
1071
1082
|
playName: state.playName,
|
|
1083
|
+
liveLogs: state.liveLogs,
|
|
1084
|
+
liveNodeProgress: state.liveNodeProgress,
|
|
1072
1085
|
ts: state.completedAt,
|
|
1073
1086
|
});
|
|
1074
1087
|
this.wakeRunEventWaiters(event);
|
|
@@ -1123,9 +1136,9 @@ export class PlayDedup implements DurableObject {
|
|
|
1123
1136
|
}
|
|
1124
1137
|
|
|
1125
1138
|
private async handleRunEventAdd(req: Request): Promise<Response> {
|
|
1126
|
-
const body = (await req
|
|
1127
|
-
|
|
1128
|
-
| null;
|
|
1139
|
+
const body = (await req
|
|
1140
|
+
.json()
|
|
1141
|
+
.catch(() => null)) as Partial<CoordinatorRunEvent> | null;
|
|
1129
1142
|
if (!body || typeof body.runId !== 'string') {
|
|
1130
1143
|
return new Response('invalid run event', { status: 400 });
|
|
1131
1144
|
}
|