deepline 0.1.243 → 0.1.244
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 +23 -21
- 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 +29 -71
- package/dist/cli/index.mjs +29 -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 +24 -22
- package/dist/index.mjs +24 -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,21 +0,0 @@
|
|
|
1
|
-
# Per-play Worker Runtime
|
|
2
|
-
|
|
3
|
-
These modules are bundled into every `esm_workers` play artifact. Keep them:
|
|
4
|
-
|
|
5
|
-
- dependency-free, except for type-only imports
|
|
6
|
-
- small enough to understand in one sitting
|
|
7
|
-
- specific to the Cloudflare Worker execution path
|
|
8
|
-
|
|
9
|
-
Do not import broad `shared_libs/play-runtime/*` modules here. Shared runtime
|
|
10
|
-
modules are optimized for the Node runner and often bring along code
|
|
11
|
-
that is correct but expensive in a per-graphHash Worker isolate.
|
|
12
|
-
|
|
13
|
-
If a helper needs zod, Neon, runtime API transport, validation registries, or
|
|
14
|
-
other heavy leaves, put it behind the `env.HARNESS` service binding in
|
|
15
|
-
`apps/play-harness-worker` and call it through `sdk/src/plays/harness-stub.ts`.
|
|
16
|
-
|
|
17
|
-
The intended split is:
|
|
18
|
-
|
|
19
|
-
- `entry.ts`: request/workflow orchestration and ctx construction
|
|
20
|
-
- `runtime/*`: tiny per-play primitives that must execute in the isolate
|
|
21
|
-
- `apps/play-harness-worker`: heavy shared leaves kept warm behind RPC
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tiny batching helpers for the per-play Worker runtime.
|
|
3
|
-
*
|
|
4
|
-
* This mirrors the small subset of shared_libs/play-runtime batching that the
|
|
5
|
-
* Workers harness needs without importing the broader shared runtime graph.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { AnyBatchOperationStrategy } from '../../../../shared_libs/play-runtime/batching-types';
|
|
9
|
-
|
|
10
|
-
export type ChunkExecutionResult<TRequest, TResult> = {
|
|
11
|
-
request: TRequest;
|
|
12
|
-
result: TResult | null;
|
|
13
|
-
/**
|
|
14
|
-
* Present when this request's execution rejected. The request failed but
|
|
15
|
-
* its siblings in the chunk kept their results — one provider hiccup must
|
|
16
|
-
* stay a per-request failure, not a chunk-level abort that discards
|
|
17
|
-
* completed sibling work.
|
|
18
|
-
*/
|
|
19
|
-
error?: unknown;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function planExecutionChunks<TRequest>(
|
|
23
|
-
requests: TRequest[],
|
|
24
|
-
batchSize: number,
|
|
25
|
-
maxChunkWeight: number | undefined,
|
|
26
|
-
weightOf: ((request: TRequest) => number) | undefined,
|
|
27
|
-
): TRequest[][] {
|
|
28
|
-
const maxUnits = Math.max(1, Math.floor(batchSize));
|
|
29
|
-
const weightCap =
|
|
30
|
-
maxChunkWeight != null && weightOf != null
|
|
31
|
-
? Math.max(1, Math.floor(maxChunkWeight))
|
|
32
|
-
: null;
|
|
33
|
-
const chunks: TRequest[][] = [];
|
|
34
|
-
let current: TRequest[] = [];
|
|
35
|
-
let weight = 0;
|
|
36
|
-
for (const request of requests) {
|
|
37
|
-
if (
|
|
38
|
-
current.length > 0 &&
|
|
39
|
-
(current.length >= maxUnits ||
|
|
40
|
-
(weightCap != null && weight >= weightCap))
|
|
41
|
-
) {
|
|
42
|
-
chunks.push(current);
|
|
43
|
-
current = [];
|
|
44
|
-
weight = 0;
|
|
45
|
-
}
|
|
46
|
-
current.push(request);
|
|
47
|
-
if (weightCap != null && weightOf != null) {
|
|
48
|
-
weight += Math.max(1, Math.floor(weightOf(request)));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if (current.length > 0) chunks.push(current);
|
|
52
|
-
return chunks;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export async function executeChunkedRequests<TRequest, TResult>(input: {
|
|
56
|
-
requests: TRequest[];
|
|
57
|
-
batchSize: number;
|
|
58
|
-
maxChunkWeight?: number;
|
|
59
|
-
weightOf?: (request: TRequest) => number;
|
|
60
|
-
execute: (request: TRequest) => Promise<TResult>;
|
|
61
|
-
onChunkComplete?: (
|
|
62
|
-
results: Array<ChunkExecutionResult<TRequest, TResult>>,
|
|
63
|
-
) => void | Promise<void>;
|
|
64
|
-
}): Promise<Array<ChunkExecutionResult<TRequest, TResult>>> {
|
|
65
|
-
const results: Array<ChunkExecutionResult<TRequest, TResult>> = [];
|
|
66
|
-
const chunks = planExecutionChunks(
|
|
67
|
-
input.requests,
|
|
68
|
-
input.batchSize,
|
|
69
|
-
input.maxChunkWeight,
|
|
70
|
-
input.weightOf,
|
|
71
|
-
);
|
|
72
|
-
for (const chunk of chunks) {
|
|
73
|
-
let notifyChain: Promise<void> = Promise.resolve();
|
|
74
|
-
const notify = async (
|
|
75
|
-
entry: ChunkExecutionResult<TRequest, TResult>,
|
|
76
|
-
): Promise<void> => {
|
|
77
|
-
results.push(entry);
|
|
78
|
-
notifyChain = notifyChain.then(
|
|
79
|
-
async () => await input.onChunkComplete?.([entry]),
|
|
80
|
-
);
|
|
81
|
-
await notifyChain;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
await Promise.all(
|
|
85
|
-
chunk.map(async (request) => {
|
|
86
|
-
let entry: ChunkExecutionResult<TRequest, TResult>;
|
|
87
|
-
try {
|
|
88
|
-
entry = { request, result: await input.execute(request) };
|
|
89
|
-
} catch (error) {
|
|
90
|
-
entry = { request, result: null, error };
|
|
91
|
-
}
|
|
92
|
-
await notify(entry);
|
|
93
|
-
}),
|
|
94
|
-
);
|
|
95
|
-
await notifyChain;
|
|
96
|
-
}
|
|
97
|
-
return results;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function compileRequestsWithStrategy<TRequest>(input: {
|
|
101
|
-
requests: TRequest[];
|
|
102
|
-
strategy: AnyBatchOperationStrategy;
|
|
103
|
-
getPayload: (request: TRequest) => Record<string, unknown>;
|
|
104
|
-
}): Array<{
|
|
105
|
-
batchOperation: string;
|
|
106
|
-
memberRequests: TRequest[];
|
|
107
|
-
batchPayload: Record<string, unknown>;
|
|
108
|
-
splitResults: (value: unknown) => Array<unknown | null>;
|
|
109
|
-
}> {
|
|
110
|
-
const compiledBatches: Array<{
|
|
111
|
-
batchOperation: string;
|
|
112
|
-
memberRequests: TRequest[];
|
|
113
|
-
batchPayload: Record<string, unknown>;
|
|
114
|
-
splitResults: (value: unknown) => Array<unknown | null>;
|
|
115
|
-
}> = [];
|
|
116
|
-
const bucketedRequests = new Map<string, TRequest[]>();
|
|
117
|
-
for (const request of input.requests) {
|
|
118
|
-
const payload = input.getPayload(request);
|
|
119
|
-
const bucketKey = String(input.strategy.toBucketKey(payload));
|
|
120
|
-
const bucket = bucketedRequests.get(bucketKey);
|
|
121
|
-
if (bucket) bucket.push(request);
|
|
122
|
-
else bucketedRequests.set(bucketKey, [request]);
|
|
123
|
-
}
|
|
124
|
-
for (const bucketRequests of bucketedRequests.values()) {
|
|
125
|
-
let currentBatch: TRequest[] = [];
|
|
126
|
-
const flushBatch = () => {
|
|
127
|
-
if (currentBatch.length === 0) return;
|
|
128
|
-
const memberRequests = [...currentBatch];
|
|
129
|
-
const compiled = input.strategy.compile(
|
|
130
|
-
memberRequests.map((request) => input.getPayload(request)),
|
|
131
|
-
);
|
|
132
|
-
compiledBatches.push({
|
|
133
|
-
batchOperation: compiled.batchOperation,
|
|
134
|
-
memberRequests,
|
|
135
|
-
batchPayload: compiled.batchPayload,
|
|
136
|
-
splitResults: (value: unknown) => {
|
|
137
|
-
const splitResults = input.strategy.splitResult(value, compiled);
|
|
138
|
-
return memberRequests.map(
|
|
139
|
-
(_, index) => splitResults[index]?.result ?? null,
|
|
140
|
-
);
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
currentBatch = [];
|
|
144
|
-
};
|
|
145
|
-
for (const request of bucketRequests) {
|
|
146
|
-
const payload = input.getPayload(request);
|
|
147
|
-
const canAppend =
|
|
148
|
-
currentBatch.length > 0 &&
|
|
149
|
-
currentBatch.length < input.strategy.maxBatchSize &&
|
|
150
|
-
currentBatch.every((existing) =>
|
|
151
|
-
input.strategy.canBatchWith(input.getPayload(existing), payload),
|
|
152
|
-
);
|
|
153
|
-
if (!canAppend && currentBatch.length > 0) flushBatch();
|
|
154
|
-
currentBatch.push(request);
|
|
155
|
-
}
|
|
156
|
-
flushBatch();
|
|
157
|
-
}
|
|
158
|
-
return compiledBatches;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function testRateLimitBatchItems(
|
|
162
|
-
value: unknown,
|
|
163
|
-
): Array<{ itemKey?: string; result?: unknown }> {
|
|
164
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
165
|
-
return [];
|
|
166
|
-
}
|
|
167
|
-
const record = value as Record<string, unknown>;
|
|
168
|
-
if (Array.isArray(record.items)) {
|
|
169
|
-
return record.items as Array<{ itemKey?: string; result?: unknown }>;
|
|
170
|
-
}
|
|
171
|
-
const candidates = [
|
|
172
|
-
record.data,
|
|
173
|
-
record.result,
|
|
174
|
-
record.output,
|
|
175
|
-
record.toolResponse &&
|
|
176
|
-
typeof record.toolResponse === 'object' &&
|
|
177
|
-
!Array.isArray(record.toolResponse)
|
|
178
|
-
? (record.toolResponse as Record<string, unknown>).raw
|
|
179
|
-
: undefined,
|
|
180
|
-
record.toolOutput &&
|
|
181
|
-
typeof record.toolOutput === 'object' &&
|
|
182
|
-
!Array.isArray(record.toolOutput)
|
|
183
|
-
? (record.toolOutput as Record<string, unknown>).raw
|
|
184
|
-
: undefined,
|
|
185
|
-
];
|
|
186
|
-
for (const candidate of candidates) {
|
|
187
|
-
const items = testRateLimitBatchItems(candidate);
|
|
188
|
-
if (items.length > 0) return items;
|
|
189
|
-
}
|
|
190
|
-
return [];
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function getDefaultPlayRuntimeBatchStrategy(
|
|
194
|
-
operation: string | null | undefined,
|
|
195
|
-
): AnyBatchOperationStrategy | null {
|
|
196
|
-
if (operation !== 'test_rate_limit') return null;
|
|
197
|
-
return {
|
|
198
|
-
sourceOperation: 'test_rate_limit',
|
|
199
|
-
batchOperation: 'test_batch_rate_limit',
|
|
200
|
-
kind: 'identifier_batch',
|
|
201
|
-
maxBatchSize: 200,
|
|
202
|
-
canBatchWith(left, right) {
|
|
203
|
-
return String(left.stage || '') === String(right.stage || '');
|
|
204
|
-
},
|
|
205
|
-
toBucketKey(payload) {
|
|
206
|
-
return `test_batch_rate_limit:${String(payload.stage || '')}`;
|
|
207
|
-
},
|
|
208
|
-
toItemKey(payload) {
|
|
209
|
-
return String(payload.lead_id || payload.row_number || payload.key || '');
|
|
210
|
-
},
|
|
211
|
-
compile(payloads) {
|
|
212
|
-
const stage = String(payloads[0]?.stage || '');
|
|
213
|
-
const simulatedDelayMs =
|
|
214
|
-
typeof payloads[0]?.simulated_delay_ms === 'number'
|
|
215
|
-
? payloads[0].simulated_delay_ms
|
|
216
|
-
: undefined;
|
|
217
|
-
const items = payloads.map((payload, index) => ({
|
|
218
|
-
itemKey: String(
|
|
219
|
-
payload.lead_id || payload.row_number || payload.key || `row_${index}`,
|
|
220
|
-
),
|
|
221
|
-
payload,
|
|
222
|
-
}));
|
|
223
|
-
return {
|
|
224
|
-
batchOperation: 'test_batch_rate_limit',
|
|
225
|
-
batchPayload: {
|
|
226
|
-
key: 'batch',
|
|
227
|
-
...(stage ? { stage } : {}),
|
|
228
|
-
...(simulatedDelayMs !== undefined
|
|
229
|
-
? { simulated_delay_ms: simulatedDelayMs }
|
|
230
|
-
: {}),
|
|
231
|
-
items,
|
|
232
|
-
},
|
|
233
|
-
items,
|
|
234
|
-
};
|
|
235
|
-
},
|
|
236
|
-
splitResult(fullResult, compiled) {
|
|
237
|
-
const resultItems = testRateLimitBatchItems(fullResult);
|
|
238
|
-
return compiled.items.map((item, index) => ({
|
|
239
|
-
itemKey: item.itemKey,
|
|
240
|
-
result:
|
|
241
|
-
index < resultItems.length
|
|
242
|
-
? (resultItems[index]?.result ?? null)
|
|
243
|
-
: null,
|
|
244
|
-
rawResult:
|
|
245
|
-
index < resultItems.length
|
|
246
|
-
? (resultItems[index]?.result ?? null)
|
|
247
|
-
: null,
|
|
248
|
-
}));
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
}
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { coordinatorRequestHeaders } from '../../../../shared_libs/play-runtime/coordinator-headers';
|
|
2
|
-
import type {
|
|
3
|
-
LiveNodeProgressMap,
|
|
4
|
-
LiveNodeProgressSnapshot,
|
|
5
|
-
} from './live-progress';
|
|
6
|
-
|
|
7
|
-
type CoordinatorProgressTraceExtra = {
|
|
8
|
-
status: 'ok' | 'failed' | 'skipped_no_url';
|
|
9
|
-
httpStatus?: number;
|
|
10
|
-
activeNodeId?: string | null;
|
|
11
|
-
activeArtifactTableNamespace?: string | null;
|
|
12
|
-
activeCompleted?: number | null;
|
|
13
|
-
activeTotal?: number | null;
|
|
14
|
-
activeMessage?: string | null;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type CoordinatorProgressTrace = {
|
|
18
|
-
phase: 'runner.coordinator_progress_publish';
|
|
19
|
-
ms: number;
|
|
20
|
-
extra: CoordinatorProgressTraceExtra;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export class CoordinatorProgressAuthorizationError extends Error {
|
|
24
|
-
constructor(
|
|
25
|
-
message: string,
|
|
26
|
-
readonly status: number,
|
|
27
|
-
) {
|
|
28
|
-
super(message);
|
|
29
|
-
this.name = 'CoordinatorProgressAuthorizationError';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function isCoordinatorProgressAuthorizationError(
|
|
34
|
-
error: unknown,
|
|
35
|
-
): error is CoordinatorProgressAuthorizationError {
|
|
36
|
-
return (
|
|
37
|
-
error instanceof CoordinatorProgressAuthorizationError ||
|
|
38
|
-
(typeof error === 'object' &&
|
|
39
|
-
error !== null &&
|
|
40
|
-
'name' in error &&
|
|
41
|
-
'status' in error &&
|
|
42
|
-
(error as { name?: unknown }).name ===
|
|
43
|
-
'CoordinatorProgressAuthorizationError' &&
|
|
44
|
-
typeof (error as { status?: unknown }).status === 'number')
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function activeProgressFields(liveNodeProgress: LiveNodeProgressMap): {
|
|
49
|
-
activeNodeId: string | null;
|
|
50
|
-
activeProgress: LiveNodeProgressSnapshot | null;
|
|
51
|
-
activeArtifactTableNamespace: string | null;
|
|
52
|
-
activeCompleted: number | null;
|
|
53
|
-
activeTotal: number | null;
|
|
54
|
-
activeMessage: string | null;
|
|
55
|
-
} {
|
|
56
|
-
const activeEntry =
|
|
57
|
-
Object.entries(liveNodeProgress).find(
|
|
58
|
-
([, progress]) => typeof progress.completedAt !== 'number',
|
|
59
|
-
) ?? Object.entries(liveNodeProgress).at(-1);
|
|
60
|
-
const activeNodeId = activeEntry?.[0] ?? null;
|
|
61
|
-
const activeProgress = activeEntry?.[1] ?? null;
|
|
62
|
-
const activeArtifactTableNamespace =
|
|
63
|
-
typeof activeProgress?.artifactTableNamespace === 'string'
|
|
64
|
-
? activeProgress.artifactTableNamespace
|
|
65
|
-
: null;
|
|
66
|
-
const activeCompleted =
|
|
67
|
-
typeof activeProgress?.completed === 'number'
|
|
68
|
-
? activeProgress.completed
|
|
69
|
-
: null;
|
|
70
|
-
const activeTotal =
|
|
71
|
-
typeof activeProgress?.total === 'number' ? activeProgress.total : null;
|
|
72
|
-
const activeMessage =
|
|
73
|
-
typeof activeProgress?.message === 'string' ? activeProgress.message : null;
|
|
74
|
-
return {
|
|
75
|
-
activeNodeId,
|
|
76
|
-
activeProgress,
|
|
77
|
-
activeArtifactTableNamespace,
|
|
78
|
-
activeCompleted,
|
|
79
|
-
activeTotal,
|
|
80
|
-
activeMessage,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function publishCoordinatorProgressEvent(input: {
|
|
85
|
-
runId: string;
|
|
86
|
-
coordinatorUrl?: string | null;
|
|
87
|
-
coordinatorInternalToken?: string | null;
|
|
88
|
-
occurredAt: number;
|
|
89
|
-
runLogBuffer: string[];
|
|
90
|
-
liveNodeProgress: LiveNodeProgressMap;
|
|
91
|
-
fetchFn: typeof fetch;
|
|
92
|
-
makeRequestId: () => string;
|
|
93
|
-
nowMs: () => number;
|
|
94
|
-
recordTrace: (trace: CoordinatorProgressTrace) => void;
|
|
95
|
-
}): Promise<void> {
|
|
96
|
-
const coordinatorUrl = input.coordinatorUrl?.trim();
|
|
97
|
-
if (!coordinatorUrl) {
|
|
98
|
-
input.recordTrace({
|
|
99
|
-
phase: 'runner.coordinator_progress_publish',
|
|
100
|
-
ms: 0,
|
|
101
|
-
extra: { status: 'skipped_no_url' },
|
|
102
|
-
});
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const publishStartedAt = input.nowMs();
|
|
107
|
-
const {
|
|
108
|
-
activeNodeId,
|
|
109
|
-
activeArtifactTableNamespace,
|
|
110
|
-
activeCompleted,
|
|
111
|
-
activeTotal,
|
|
112
|
-
activeMessage,
|
|
113
|
-
} = activeProgressFields(input.liveNodeProgress);
|
|
114
|
-
|
|
115
|
-
const response = await input.fetchFn(
|
|
116
|
-
`${coordinatorUrl.replace(/\/$/, '')}/dedup/${encodeURIComponent(
|
|
117
|
-
input.runId,
|
|
118
|
-
)}/event-add`,
|
|
119
|
-
{
|
|
120
|
-
method: 'POST',
|
|
121
|
-
headers: {
|
|
122
|
-
'x-deepline-request-id': input.makeRequestId(),
|
|
123
|
-
...coordinatorRequestHeaders({
|
|
124
|
-
runId: input.runId,
|
|
125
|
-
contentType: 'application/json',
|
|
126
|
-
internalToken: input.coordinatorInternalToken,
|
|
127
|
-
}),
|
|
128
|
-
},
|
|
129
|
-
body: JSON.stringify({
|
|
130
|
-
runId: input.runId,
|
|
131
|
-
type: 'progress',
|
|
132
|
-
status: 'running',
|
|
133
|
-
ts: input.occurredAt,
|
|
134
|
-
logs: input.runLogBuffer,
|
|
135
|
-
activeNodeId,
|
|
136
|
-
activeArtifactTableNamespace,
|
|
137
|
-
updatedAt: input.occurredAt,
|
|
138
|
-
liveNodeProgress: input.liveNodeProgress,
|
|
139
|
-
}),
|
|
140
|
-
},
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
if (response.status === 401 || response.status === 403) {
|
|
144
|
-
input.recordTrace({
|
|
145
|
-
phase: 'runner.coordinator_progress_publish',
|
|
146
|
-
ms: input.nowMs() - publishStartedAt,
|
|
147
|
-
extra: {
|
|
148
|
-
status: 'failed',
|
|
149
|
-
httpStatus: response.status,
|
|
150
|
-
activeNodeId,
|
|
151
|
-
activeArtifactTableNamespace,
|
|
152
|
-
activeCompleted,
|
|
153
|
-
activeTotal,
|
|
154
|
-
activeMessage,
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
throw new CoordinatorProgressAuthorizationError(
|
|
158
|
-
`Coordinator progress publish was rejected with ${response.status}; ` +
|
|
159
|
-
'the play runner no longer has authority to update its coordinator state. ' +
|
|
160
|
-
'Stopping before more provider work can execute with stale coordinator authority.',
|
|
161
|
-
response.status,
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (!response.ok) {
|
|
166
|
-
input.recordTrace({
|
|
167
|
-
phase: 'runner.coordinator_progress_publish',
|
|
168
|
-
ms: input.nowMs() - publishStartedAt,
|
|
169
|
-
extra: {
|
|
170
|
-
status: 'failed',
|
|
171
|
-
httpStatus: response.status,
|
|
172
|
-
activeNodeId,
|
|
173
|
-
activeArtifactTableNamespace,
|
|
174
|
-
activeCompleted,
|
|
175
|
-
activeTotal,
|
|
176
|
-
activeMessage,
|
|
177
|
-
},
|
|
178
|
-
});
|
|
179
|
-
throw new Error(`coordinator progress event failed ${response.status}`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
input.recordTrace({
|
|
183
|
-
phase: 'runner.coordinator_progress_publish',
|
|
184
|
-
ms: input.nowMs() - publishStartedAt,
|
|
185
|
-
extra: {
|
|
186
|
-
status: 'ok',
|
|
187
|
-
activeNodeId,
|
|
188
|
-
activeArtifactTableNamespace,
|
|
189
|
-
activeCompleted,
|
|
190
|
-
activeTotal,
|
|
191
|
-
activeMessage,
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function createCoordinatorProgressPublisher(input: {
|
|
197
|
-
runId: string;
|
|
198
|
-
coordinatorUrl?: string | null;
|
|
199
|
-
coordinatorInternalToken?: string | null;
|
|
200
|
-
abortController: AbortController;
|
|
201
|
-
getRunLogBuffer: () => string[];
|
|
202
|
-
getLiveNodeProgress: () => LiveNodeProgressMap;
|
|
203
|
-
recordTrace: (trace: CoordinatorProgressTrace) => void;
|
|
204
|
-
fetchFn?: typeof fetch;
|
|
205
|
-
makeRequestId: () => string;
|
|
206
|
-
nowMs: () => number;
|
|
207
|
-
heartbeatIntervalMs: number;
|
|
208
|
-
}): {
|
|
209
|
-
assertHealthy: () => void;
|
|
210
|
-
flush: (force: boolean) => Promise<void>;
|
|
211
|
-
fatalError: () => Error | null;
|
|
212
|
-
} {
|
|
213
|
-
let lastPublishAt = 0;
|
|
214
|
-
let publishInFlight: Promise<void> = Promise.resolve();
|
|
215
|
-
let publishQueueDepth = 0;
|
|
216
|
-
let fatalError: Error | null = null;
|
|
217
|
-
const abortSignal = input.abortController.signal;
|
|
218
|
-
const fetchFn = input.fetchFn ?? fetch;
|
|
219
|
-
|
|
220
|
-
const markFatal = (error: Error): void => {
|
|
221
|
-
fatalError ??= error;
|
|
222
|
-
if (!abortSignal.aborted) {
|
|
223
|
-
input.abortController.abort(error);
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
const assertHealthy = (): void => {
|
|
228
|
-
if (fatalError) {
|
|
229
|
-
throw fatalError;
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
const publish = async (occurredAt: number): Promise<void> => {
|
|
234
|
-
assertHealthy();
|
|
235
|
-
await publishCoordinatorProgressEvent({
|
|
236
|
-
runId: input.runId,
|
|
237
|
-
coordinatorUrl: input.coordinatorUrl,
|
|
238
|
-
coordinatorInternalToken: input.coordinatorInternalToken,
|
|
239
|
-
occurredAt,
|
|
240
|
-
runLogBuffer: input.getRunLogBuffer(),
|
|
241
|
-
liveNodeProgress: input.getLiveNodeProgress(),
|
|
242
|
-
fetchFn,
|
|
243
|
-
makeRequestId: input.makeRequestId,
|
|
244
|
-
nowMs: input.nowMs,
|
|
245
|
-
recordTrace: input.recordTrace,
|
|
246
|
-
});
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const flush = (force: boolean): Promise<void> => {
|
|
250
|
-
if (fatalError) {
|
|
251
|
-
return force ? Promise.reject(fatalError) : Promise.resolve();
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const now = input.nowMs();
|
|
255
|
-
if (!force && now - lastPublishAt < input.heartbeatIntervalMs) {
|
|
256
|
-
return Promise.resolve();
|
|
257
|
-
}
|
|
258
|
-
if (!force && publishQueueDepth > 0) {
|
|
259
|
-
return Promise.resolve();
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
lastPublishAt = now;
|
|
263
|
-
publishQueueDepth += 1;
|
|
264
|
-
const publishTask = publishInFlight
|
|
265
|
-
.catch(() => undefined)
|
|
266
|
-
.then(async () => {
|
|
267
|
-
try {
|
|
268
|
-
await publish(now);
|
|
269
|
-
} finally {
|
|
270
|
-
publishQueueDepth = Math.max(0, publishQueueDepth - 1);
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
const handledPublishTask = publishTask.catch((error) => {
|
|
275
|
-
if (isCoordinatorProgressAuthorizationError(error)) {
|
|
276
|
-
markFatal(error);
|
|
277
|
-
throw error;
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
publishInFlight = handledPublishTask.catch(() => undefined);
|
|
281
|
-
return force ? handledPublishTask : Promise.resolve();
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
assertHealthy,
|
|
286
|
-
flush,
|
|
287
|
-
fatalError: () => fatalError,
|
|
288
|
-
};
|
|
289
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
cloneCsvAliasedRow,
|
|
3
|
-
stripCsvProjectionMetadata,
|
|
4
|
-
} from '../../../../shared_libs/play-runtime/csv-rename';
|
|
5
|
-
import { copyMapRowOutcomeRuntimeFields } from '../../../../shared_libs/play-runtime/map-row-outcome';
|
|
6
|
-
|
|
7
|
-
const CSV_TEMPLATE_CONTEXT = '__deeplineCsvProjectedValues';
|
|
8
|
-
|
|
9
|
-
export type CsvRuntimeRow = Record<string, unknown>;
|
|
10
|
-
|
|
11
|
-
function copyVisibleFields(
|
|
12
|
-
row: CsvRuntimeRow,
|
|
13
|
-
keepTemplateContext: boolean,
|
|
14
|
-
): CsvRuntimeRow {
|
|
15
|
-
const publicRow: CsvRuntimeRow = {};
|
|
16
|
-
for (const fieldName of Reflect.ownKeys(row)) {
|
|
17
|
-
if (
|
|
18
|
-
typeof fieldName === 'string' &&
|
|
19
|
-
fieldName.startsWith('__deepline') &&
|
|
20
|
-
(!keepTemplateContext || fieldName !== CSV_TEMPLATE_CONTEXT)
|
|
21
|
-
) {
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
const descriptor = Object.getOwnPropertyDescriptor(row, fieldName);
|
|
25
|
-
if (!descriptor) continue;
|
|
26
|
-
Object.defineProperty(publicRow, fieldName, descriptor);
|
|
27
|
-
}
|
|
28
|
-
return publicRow;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function withCtx(
|
|
32
|
-
row: CsvRuntimeRow,
|
|
33
|
-
contextSource: CsvRuntimeRow = row,
|
|
34
|
-
): CsvRuntimeRow {
|
|
35
|
-
const ctx = contextSource[CSV_TEMPLATE_CONTEXT];
|
|
36
|
-
if (ctx) {
|
|
37
|
-
const values = ctx as CsvRuntimeRow;
|
|
38
|
-
for (const fieldName in values) {
|
|
39
|
-
delete row[fieldName];
|
|
40
|
-
row[fieldName] = values[fieldName];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return row;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function publicCsvInputRow<T extends CsvRuntimeRow>(row: T): T {
|
|
47
|
-
return copyVisibleFields(stripCsvProjectionMetadata(row), false) as T;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function runtimeCsvInputRow<T extends CsvRuntimeRow>(row: T): T {
|
|
51
|
-
return withCtx(copyVisibleFields(cloneCsvAliasedRow(row), true)) as T;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function runtimeCsvExecutionRow<T extends CsvRuntimeRow>(
|
|
55
|
-
sourceRow: T,
|
|
56
|
-
pendingRow?: CsvRuntimeRow | null,
|
|
57
|
-
): T {
|
|
58
|
-
const source = runtimeCsvInputRow(sourceRow) as CsvRuntimeRow;
|
|
59
|
-
if (!pendingRow) return source as T;
|
|
60
|
-
const pending = runtimeCsvInputRow(pendingRow);
|
|
61
|
-
const executionRow = { ...pending, ...source };
|
|
62
|
-
if ('__deeplineCellMeta' in pendingRow) {
|
|
63
|
-
executionRow.__deeplineCellMeta = pendingRow.__deeplineCellMeta;
|
|
64
|
-
}
|
|
65
|
-
return withCtx(executionRow) as T;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function publicCsvOutputRow<T extends CsvRuntimeRow>(row: T): T {
|
|
69
|
-
return publicCsvInputRow(row);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function publicCsvStorageRow<T extends CsvRuntimeRow>(row: T): T {
|
|
73
|
-
const publicRow = publicCsvInputRow(row) as CsvRuntimeRow;
|
|
74
|
-
const storageRow: CsvRuntimeRow = {};
|
|
75
|
-
for (const fieldName of Reflect.ownKeys(publicRow)) {
|
|
76
|
-
if (typeof fieldName !== 'string') continue;
|
|
77
|
-
storageRow[fieldName] = publicRow[fieldName];
|
|
78
|
-
}
|
|
79
|
-
return copyMapRowOutcomeRuntimeFields(storageRow, row) as T;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function runtimeCsvStorageRow<T extends CsvRuntimeRow>(row: T): T {
|
|
83
|
-
const storageRow = publicCsvStorageRow(row) as CsvRuntimeRow;
|
|
84
|
-
return withCtx(storageRow, row) as T;
|
|
85
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export function formatCustomerConsoleValue(value: unknown): string {
|
|
2
|
-
if (typeof value === 'string') return value;
|
|
3
|
-
try {
|
|
4
|
-
if (value instanceof Error) return value.stack ?? value.message;
|
|
5
|
-
if (value && typeof value === 'object') {
|
|
6
|
-
const seen = new WeakSet<object>();
|
|
7
|
-
const serialized = JSON.stringify(value, (_key, nested) => {
|
|
8
|
-
if (typeof nested === 'symbol' || typeof nested === 'bigint') {
|
|
9
|
-
return nested.toString();
|
|
10
|
-
}
|
|
11
|
-
if (nested && typeof nested === 'object') {
|
|
12
|
-
if (seen.has(nested)) return '[Circular]';
|
|
13
|
-
seen.add(nested);
|
|
14
|
-
}
|
|
15
|
-
return nested;
|
|
16
|
-
});
|
|
17
|
-
if (serialized !== undefined) return serialized;
|
|
18
|
-
}
|
|
19
|
-
return String(value);
|
|
20
|
-
} catch {
|
|
21
|
-
return '[Unprintable]';
|
|
22
|
-
}
|
|
23
|
-
}
|