deepline 0.3.289 → 0.3.291
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 +8 -6
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/runs/overview.ts +16 -6
- package/dist/bundling-sources/sdk/src/types.ts +21 -2
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +41 -11
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +317 -63
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +10 -2
- package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/log-context.ts +36 -0
- package/dist/bundling-sources/shared_libs/play-runtime/log-provenance.ts +19 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/worker-terminal-projection.ts +6 -5
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +12 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-event-catalog.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts +74 -33
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +73 -3
- package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +39 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +72 -9
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +77 -10
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool-options.ts +145 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +17 -9
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -139
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +19 -5
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +176 -18
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +7 -5
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1404 -478
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +55 -25
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +97 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +34 -15
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +558 -57
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +10 -1
- package/dist/bundling-sources/shared_libs/play-runtime/step-progress.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/test-admission-batching.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +22 -5
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +35 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +68 -8
- package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/zerobounce-batching.ts +75 -28
- package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +2 -0
- package/dist/cli/index.js +195 -582
- package/dist/cli/index.mjs +195 -582
- package/dist/{client-FR_u0dxT.d.ts → client-Ct4jmvAg.d.ts} +29 -8
- package/dist/{client-phK1Ixcl.d.mts → client-Ct9GKrwu.d.mts} +29 -8
- package/dist/{compiler-manifest-9SQtUuKb.d.mts → compiler-manifest-qtTNYvBl.d.mts} +2 -0
- package/dist/{compiler-manifest-9SQtUuKb.d.ts → compiler-manifest-qtTNYvBl.d.ts} +2 -0
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +14 -5
- package/dist/index.mjs +14 -5
- package/dist/install-integrity.json +7 -4
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/run-request.d.mts +2 -2
- package/dist/plays/run-request.d.ts +2 -2
- 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
|
@@ -36,7 +36,10 @@ import {
|
|
|
36
36
|
DURABLE_INVOCATION_FENCE_ATTESTATION_VALUE,
|
|
37
37
|
} from '../durable-invocation-fence';
|
|
38
38
|
import type { PlayRunInputPayload } from '../play-input';
|
|
39
|
-
import type {
|
|
39
|
+
import type {
|
|
40
|
+
PlayLogContext,
|
|
41
|
+
PlayLogMetadata,
|
|
42
|
+
} from '../log-context';
|
|
40
43
|
import { playRunInputObjectView } from '../play-input';
|
|
41
44
|
import {
|
|
42
45
|
normalizePlayRunFailure,
|
|
@@ -1737,6 +1740,13 @@ async function executeRuntimePlayCode(input: {
|
|
|
1737
1740
|
}
|
|
1738
1741
|
|
|
1739
1742
|
const CAPTURED_CONSOLE_MAX_CHARS = 2_000;
|
|
1743
|
+
const CAPTURED_CONSOLE_PREFIX_RESERVE_CHARS = 64;
|
|
1744
|
+
const CAPTURED_CONSOLE_SHORTENED_MARKER =
|
|
1745
|
+
'… [log shortened; save complete values in a dataset and use runs export]';
|
|
1746
|
+
const CAPTURED_CONSOLE_MAX_MESSAGE_CHARS =
|
|
1747
|
+
CAPTURED_CONSOLE_MAX_CHARS - CAPTURED_CONSOLE_PREFIX_RESERVE_CHARS;
|
|
1748
|
+
const CAPTURED_CONSOLE_FORMAT_TRUNCATION =
|
|
1749
|
+
/(\.\.\.|…)\s*\d+\s+more\s+(?:characters?|items?)/i;
|
|
1740
1750
|
|
|
1741
1751
|
function logLevelForCapturedConsoleMethod(
|
|
1742
1752
|
method: string,
|
|
@@ -1763,14 +1773,20 @@ function createCapturedCustomerConsole(
|
|
|
1763
1773
|
compact: true,
|
|
1764
1774
|
depth: 4,
|
|
1765
1775
|
maxArrayLength: 20,
|
|
1766
|
-
maxStringLength:
|
|
1776
|
+
maxStringLength: CAPTURED_CONSOLE_MAX_MESSAGE_CHARS,
|
|
1767
1777
|
},
|
|
1768
1778
|
...args,
|
|
1769
1779
|
);
|
|
1770
|
-
const
|
|
1771
|
-
formatted.length >
|
|
1772
|
-
|
|
1773
|
-
|
|
1780
|
+
const shortened =
|
|
1781
|
+
formatted.length > CAPTURED_CONSOLE_MAX_MESSAGE_CHARS ||
|
|
1782
|
+
CAPTURED_CONSOLE_FORMAT_TRUNCATION.test(formatted);
|
|
1783
|
+
const message = shortened
|
|
1784
|
+
? `${formatted.slice(
|
|
1785
|
+
0,
|
|
1786
|
+
CAPTURED_CONSOLE_MAX_MESSAGE_CHARS -
|
|
1787
|
+
CAPTURED_CONSOLE_SHORTENED_MARKER.length,
|
|
1788
|
+
)}${CAPTURED_CONSOLE_SHORTENED_MARKER}`
|
|
1789
|
+
: formatted;
|
|
1774
1790
|
ctx.log(`[console.${method}] ${message}`, {
|
|
1775
1791
|
level: logLevelForCapturedConsoleMethod(method),
|
|
1776
1792
|
});
|
|
@@ -1903,6 +1919,14 @@ async function releaseRuntimeLeasesOnAppRunnerSettlement(input: {
|
|
|
1903
1919
|
}
|
|
1904
1920
|
}
|
|
1905
1921
|
|
|
1922
|
+
function terminalLogIdsWithPhaseSummary(ctx: {
|
|
1923
|
+
getLogIds(): string[];
|
|
1924
|
+
}): string[] {
|
|
1925
|
+
// Summaries are new occurrences at result construction. Terminal retries
|
|
1926
|
+
// reuse that result and its IDs, including the frozen summary bodies.
|
|
1927
|
+
return [...ctx.getLogIds(), crypto.randomUUID(), crypto.randomUUID()];
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1906
1930
|
function terminalLogsWithPhaseSummary(ctx: {
|
|
1907
1931
|
getLogs(): string[];
|
|
1908
1932
|
getRuntimeResourceSnapshot(): unknown;
|
|
@@ -1915,6 +1939,13 @@ function terminalLogsWithPhaseSummary(ctx: {
|
|
|
1915
1939
|
];
|
|
1916
1940
|
}
|
|
1917
1941
|
|
|
1942
|
+
function terminalLogMetadataWithPhaseSummary(ctx: {
|
|
1943
|
+
getLogMetadata(): Array<PlayLogMetadata | null>;
|
|
1944
|
+
}): Array<PlayLogMetadata | null> | undefined {
|
|
1945
|
+
const metadata = ctx.getLogMetadata();
|
|
1946
|
+
return metadata.some(Boolean) ? [...metadata, null, null] : undefined;
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1918
1949
|
function terminalLogContextsWithPhaseSummary(ctx: {
|
|
1919
1950
|
getLogContexts(): Array<PlayLogContext | null>;
|
|
1920
1951
|
}): Array<PlayLogContext | null> | undefined {
|
|
@@ -2488,7 +2519,7 @@ async function run(
|
|
|
2488
2519
|
});
|
|
2489
2520
|
}
|
|
2490
2521
|
: undefined,
|
|
2491
|
-
onLog: (line, context) => {
|
|
2522
|
+
onLog: (line, context, entryId, metadata) => {
|
|
2492
2523
|
const timestampMatch = line.match(/^\[([^\]]+)\]/);
|
|
2493
2524
|
const timestamp = timestampMatch?.[1];
|
|
2494
2525
|
const at =
|
|
@@ -2501,7 +2532,11 @@ async function run(
|
|
|
2501
2532
|
at,
|
|
2502
2533
|
source: 'play',
|
|
2503
2534
|
line,
|
|
2535
|
+
...(config.context.runtimeLogIdentity === 'origin' && entryId
|
|
2536
|
+
? { entryId }
|
|
2537
|
+
: {}),
|
|
2504
2538
|
...(context ? { context } : {}),
|
|
2539
|
+
...(metadata ? { metadata } : {}),
|
|
2505
2540
|
},
|
|
2506
2541
|
options,
|
|
2507
2542
|
);
|
|
@@ -3128,7 +3163,11 @@ async function run(
|
|
|
3128
3163
|
error: runtimeLimitExceededCause(runtimeLimitSeconds),
|
|
3129
3164
|
errors: [runtimeLimitExceededFailure(runtimeLimitSeconds)],
|
|
3130
3165
|
logs: terminalLogsWithPhaseSummary(ctx),
|
|
3166
|
+
...(config.context.runtimeLogIdentity === 'origin'
|
|
3167
|
+
? { logIds: terminalLogIdsWithPhaseSummary(ctx) }
|
|
3168
|
+
: {}),
|
|
3131
3169
|
logContexts: terminalLogContextsWithPhaseSummary(ctx),
|
|
3170
|
+
logMetadata: terminalLogMetadataWithPhaseSummary(ctx),
|
|
3132
3171
|
stats: runtimeStats(),
|
|
3133
3172
|
steps: ctx.getSteps(),
|
|
3134
3173
|
tableNamespace: null,
|
|
@@ -3372,7 +3411,11 @@ async function run(
|
|
|
3372
3411
|
: {}),
|
|
3373
3412
|
outputRowCount,
|
|
3374
3413
|
logs,
|
|
3414
|
+
...(config.context.runtimeLogIdentity === 'origin'
|
|
3415
|
+
? { logIds: terminalLogIdsWithPhaseSummary(ctx) }
|
|
3416
|
+
: {}),
|
|
3375
3417
|
logContexts: terminalLogContextsWithPhaseSummary(ctx),
|
|
3418
|
+
logMetadata: terminalLogMetadataWithPhaseSummary(ctx),
|
|
3376
3419
|
...(runtimeDiagnostics.length > 0 ? { runtimeDiagnostics } : {}),
|
|
3377
3420
|
...(rowOutcomes ? { rowOutcomes } : {}),
|
|
3378
3421
|
stats: runtimeStats(),
|
|
@@ -3427,7 +3470,11 @@ async function run(
|
|
|
3427
3470
|
status: 'suspended',
|
|
3428
3471
|
suspension: error.suspension,
|
|
3429
3472
|
logs: terminalLogsWithPhaseSummary(ctx),
|
|
3473
|
+
...(config.context.runtimeLogIdentity === 'origin'
|
|
3474
|
+
? { logIds: terminalLogIdsWithPhaseSummary(ctx) }
|
|
3475
|
+
: {}),
|
|
3430
3476
|
logContexts: terminalLogContextsWithPhaseSummary(ctx),
|
|
3477
|
+
logMetadata: terminalLogMetadataWithPhaseSummary(ctx),
|
|
3431
3478
|
stats: runtimeStats(),
|
|
3432
3479
|
steps: ctx.getSteps(),
|
|
3433
3480
|
checkpoint: ctx.getCheckpoint(),
|
|
@@ -3463,7 +3510,11 @@ async function run(
|
|
|
3463
3510
|
error: formatRunnerFailure(error),
|
|
3464
3511
|
errors: [failure],
|
|
3465
3512
|
logs: terminalLogsWithPhaseSummary(ctx),
|
|
3513
|
+
...(config.context.runtimeLogIdentity === 'origin'
|
|
3514
|
+
? { logIds: terminalLogIdsWithPhaseSummary(ctx) }
|
|
3515
|
+
: {}),
|
|
3466
3516
|
logContexts: terminalLogContextsWithPhaseSummary(ctx),
|
|
3517
|
+
logMetadata: terminalLogMetadataWithPhaseSummary(ctx),
|
|
3467
3518
|
...(rowOutcomes ? { rowOutcomes } : {}),
|
|
3468
3519
|
stats: runtimeStats(),
|
|
3469
3520
|
steps: ctx.getSteps(),
|
|
@@ -3483,11 +3534,23 @@ export async function executePlayRunner(
|
|
|
3483
3534
|
config: PlayRunnerExecutionConfig,
|
|
3484
3535
|
options?: ExecutePlayRunnerOptions,
|
|
3485
3536
|
): Promise<PlayRunnerResult> {
|
|
3486
|
-
const
|
|
3537
|
+
const emissionOptions: ExecutePlayRunnerOptions = {
|
|
3538
|
+
...options,
|
|
3539
|
+
emitEvent: (event) =>
|
|
3540
|
+
emitRunnerEvent(
|
|
3541
|
+
config.context.runtimeLogIdentity === 'origin' &&
|
|
3542
|
+
event.type === 'log' &&
|
|
3543
|
+
!event.entryId
|
|
3544
|
+
? { ...event, entryId: crypto.randomUUID() }
|
|
3545
|
+
: event,
|
|
3546
|
+
options,
|
|
3547
|
+
),
|
|
3548
|
+
};
|
|
3549
|
+
const result = await run(config, emissionOptions);
|
|
3487
3550
|
// Inline-executor mirror of the child terminal drain: the caller's finalize
|
|
3488
3551
|
// reads the observations table right after this returns, so land in-flight
|
|
3489
3552
|
// observation posts first (bounded, best-effort, docflow-gated by emptiness).
|
|
3490
|
-
await drainPendingDocflowObservationPosts(
|
|
3553
|
+
await drainPendingDocflowObservationPosts(emissionOptions);
|
|
3491
3554
|
return result;
|
|
3492
3555
|
}
|
|
3493
3556
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PlayRunnerEvent } from '../protocol';
|
|
2
|
+
import { isDurableDirectRunnerLog } from '../log-provenance';
|
|
2
3
|
import { jsonByteLengthUpTo } from '../output-size-limits';
|
|
3
4
|
import { RUNTIME_RUNNER_TERMINAL_PROGRESS_MAX_EVENTS } from '../runtime-contract';
|
|
4
5
|
|
|
@@ -116,9 +117,7 @@ type PendingEvent = {
|
|
|
116
117
|
};
|
|
117
118
|
|
|
118
119
|
function isDurableLog(event: PlayRunnerEvent): boolean {
|
|
119
|
-
return (
|
|
120
|
-
event.type === 'log' && event.source !== 'worker' && event.line.length > 0
|
|
121
|
-
);
|
|
120
|
+
return event.type === 'log' && isDurableDirectRunnerLog(event);
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
export function createRunnerProgressPusher(
|
|
@@ -3,7 +3,10 @@ import {
|
|
|
3
3
|
type PlayRunnerEvent,
|
|
4
4
|
type PlayRunnerResult,
|
|
5
5
|
} from '../protocol';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
PlayLogContext,
|
|
8
|
+
PlayLogMetadata,
|
|
9
|
+
} from '../log-context';
|
|
7
10
|
import { parseCtxFetchHttpFailureDiagnostic } from '../log-provenance';
|
|
8
11
|
import {
|
|
9
12
|
RUNNER_TERMINAL_PUSH_MAX_BODY_BYTES,
|
|
@@ -201,9 +204,14 @@ function retainArrayWithinJsonByteLimit<T>(
|
|
|
201
204
|
* Retain the normal newest log tail, but reserve space for the canonical
|
|
202
205
|
* ctx.fetch failure diagnostics first. `runtimeDiagnostics` powers the final
|
|
203
206
|
* warning, while the matching raw log line is the durable evidence customers
|
|
204
|
-
* see through `runs logs
|
|
207
|
+
* see through `runs logs` after progress events could not be pushed.
|
|
205
208
|
*/
|
|
206
|
-
function retainTerminalLogTailWithRuntimeDiagnostics(
|
|
209
|
+
function retainTerminalLogTailWithRuntimeDiagnostics(
|
|
210
|
+
logs: readonly string[],
|
|
211
|
+
logContexts?: readonly (PlayLogContext | null)[],
|
|
212
|
+
logMetadata?: readonly (PlayLogMetadata | null)[],
|
|
213
|
+
logIds?: readonly string[],
|
|
214
|
+
): {
|
|
207
215
|
values: string[];
|
|
208
216
|
indexes: number[];
|
|
209
217
|
truncated: boolean;
|
|
@@ -215,8 +223,16 @@ function retainTerminalLogTailWithRuntimeDiagnostics(logs: readonly string[]): {
|
|
|
215
223
|
// array. Re-serializing the retained 128 KiB tail for every historical
|
|
216
224
|
// line made large completed runs exhaust their terminal-flush deadline.
|
|
217
225
|
const separatorBytes = retainedIndexes.size ? 1 : 0;
|
|
218
|
-
|
|
226
|
+
// The aligned arrays cross this same transport. Counting their bytes
|
|
227
|
+
// preserves the existing diagnostic allowance and customer-output headroom.
|
|
228
|
+
const entry = [
|
|
219
229
|
logs[index]!,
|
|
230
|
+
...(logContexts ? [logContexts[index] ?? null] : []),
|
|
231
|
+
...(logMetadata ? [logMetadata[index] ?? null] : []),
|
|
232
|
+
...(logIds ? [logIds[index]] : []),
|
|
233
|
+
];
|
|
234
|
+
const measurement = jsonByteLengthUpTo(
|
|
235
|
+
entry.length === 1 ? entry[0] : entry,
|
|
220
236
|
TERMINAL_TRANSPORT_LOG_TAIL_MAX_BYTES - retainedBytes - separatorBytes,
|
|
221
237
|
);
|
|
222
238
|
if (measurement.exceeded) return;
|
|
@@ -269,15 +285,30 @@ function appendTerminalDiagnosticsMarker(
|
|
|
269
285
|
logs: string[],
|
|
270
286
|
truncatedFields: string[],
|
|
271
287
|
logContexts?: Array<PlayLogContext | null>,
|
|
272
|
-
|
|
288
|
+
logIds?: string[],
|
|
289
|
+
logMetadata?: Array<PlayLogMetadata | null>,
|
|
290
|
+
): {
|
|
291
|
+
logs: string[];
|
|
292
|
+
logContexts?: Array<PlayLogContext | null>;
|
|
293
|
+
logIds?: string[];
|
|
294
|
+
logMetadata?: Array<PlayLogMetadata | null>;
|
|
295
|
+
} {
|
|
273
296
|
const marker =
|
|
274
297
|
`[deepline] terminal diagnostic metadata was bounded (${truncatedFields.join(', ')}); ` +
|
|
275
298
|
'the authored play output is complete.';
|
|
276
299
|
const marked = [marker, ...logs];
|
|
277
300
|
const markedContexts = logContexts ? [null, ...logContexts] : undefined;
|
|
301
|
+
const markedMetadata = logMetadata ? [null, ...logMetadata] : undefined;
|
|
302
|
+
const markedIds = logIds ? [crypto.randomUUID(), ...logIds] : undefined;
|
|
303
|
+
const logPayload = () => ({
|
|
304
|
+
logs: marked,
|
|
305
|
+
...(markedContexts ? { logContexts: markedContexts } : {}),
|
|
306
|
+
...(markedMetadata ? { logMetadata: markedMetadata } : {}),
|
|
307
|
+
...(markedIds ? { logIds: markedIds } : {}),
|
|
308
|
+
});
|
|
278
309
|
while (
|
|
279
310
|
marked.length > 1 &&
|
|
280
|
-
!fitsJsonByteLimit(
|
|
311
|
+
!fitsJsonByteLimit(logPayload(), TERMINAL_TRANSPORT_LOG_TAIL_MAX_BYTES)
|
|
281
312
|
) {
|
|
282
313
|
// Preserve canonical ctx.fetch evidence when a marker itself needs room.
|
|
283
314
|
// Other tail lines are diagnostic context, but this line is the durable
|
|
@@ -289,15 +320,23 @@ function appendTerminalDiagnosticsMarker(
|
|
|
289
320
|
const removeAt = removableIndex === -1 ? 1 : removableIndex;
|
|
290
321
|
marked.splice(removeAt, 1);
|
|
291
322
|
markedContexts?.splice(removeAt, 1);
|
|
323
|
+
markedMetadata?.splice(removeAt, 1);
|
|
324
|
+
markedIds?.splice(removeAt, 1);
|
|
292
325
|
}
|
|
293
326
|
const logsFit = fitsJsonByteLimit(
|
|
294
|
-
|
|
327
|
+
logPayload(),
|
|
295
328
|
TERMINAL_TRANSPORT_LOG_TAIL_MAX_BYTES,
|
|
296
329
|
);
|
|
297
330
|
const retainedLogs = logsFit ? marked : [marker];
|
|
298
331
|
const retainedContexts = logsFit ? markedContexts : [null];
|
|
299
332
|
return {
|
|
300
333
|
logs: retainedLogs,
|
|
334
|
+
...(markedMetadata?.some(Boolean)
|
|
335
|
+
? { logMetadata: logsFit ? markedMetadata : [null] }
|
|
336
|
+
: {}),
|
|
337
|
+
...(markedIds
|
|
338
|
+
? { logIds: logsFit ? markedIds : markedIds.slice(0, 1) }
|
|
339
|
+
: {}),
|
|
301
340
|
...(retainedContexts?.some(Boolean)
|
|
302
341
|
? { logContexts: retainedContexts }
|
|
303
342
|
: {}),
|
|
@@ -313,18 +352,34 @@ function appendTerminalDiagnosticsMarker(
|
|
|
313
352
|
function boundSettledTerminalTransportDiagnostics(
|
|
314
353
|
result: SettledRunnerTerminalTransportResult,
|
|
315
354
|
): SettledRunnerTerminalTransportResult {
|
|
316
|
-
const logProjection = retainTerminalLogTailWithRuntimeDiagnostics(
|
|
317
|
-
result.logs,
|
|
318
|
-
);
|
|
319
355
|
if (
|
|
320
356
|
result.logContexts !== undefined &&
|
|
321
357
|
result.logContexts.length !== result.logs.length
|
|
322
358
|
) {
|
|
323
359
|
throw new TypeError('Terminal log contexts must align with result logs.');
|
|
324
360
|
}
|
|
361
|
+
if (
|
|
362
|
+
result.logMetadata !== undefined &&
|
|
363
|
+
result.logMetadata.length !== result.logs.length
|
|
364
|
+
)
|
|
365
|
+
throw new TypeError('Terminal log metadata must align with logs.');
|
|
366
|
+
const logProjection = retainTerminalLogTailWithRuntimeDiagnostics(
|
|
367
|
+
result.logs,
|
|
368
|
+
result.logContexts,
|
|
369
|
+
result.logMetadata,
|
|
370
|
+
result.logIds,
|
|
371
|
+
);
|
|
325
372
|
const logContexts = result.logContexts?.length
|
|
326
373
|
? logProjection.indexes.map((index) => result.logContexts![index] ?? null)
|
|
327
374
|
: undefined;
|
|
375
|
+
const logMetadata = result.logMetadata?.length
|
|
376
|
+
? logProjection.indexes.map((index) => result.logMetadata![index] ?? null)
|
|
377
|
+
: undefined;
|
|
378
|
+
if (result.logIds && result.logIds.length !== result.logs.length)
|
|
379
|
+
throw new TypeError('Terminal log identities must align with result logs.');
|
|
380
|
+
const logIds = result.logIds
|
|
381
|
+
? logProjection.indexes.map((index) => result.logIds![index]!)
|
|
382
|
+
: undefined;
|
|
328
383
|
const statsProjection = retainRecordWithinJsonByteLimit(
|
|
329
384
|
result.stats,
|
|
330
385
|
TERMINAL_TRANSPORT_STATS_MAX_BYTES,
|
|
@@ -368,15 +423,21 @@ function boundSettledTerminalTransportDiagnostics(
|
|
|
368
423
|
logProjection.values,
|
|
369
424
|
truncatedFields,
|
|
370
425
|
logContexts,
|
|
426
|
+
logIds,
|
|
427
|
+
logMetadata,
|
|
371
428
|
)
|
|
372
429
|
: {
|
|
373
430
|
logs: logProjection.values,
|
|
431
|
+
...(logIds ? { logIds } : {}),
|
|
374
432
|
...(logContexts?.some(Boolean) ? { logContexts } : {}),
|
|
433
|
+
...(logMetadata?.some(Boolean) ? { logMetadata } : {}),
|
|
375
434
|
};
|
|
376
435
|
return {
|
|
377
436
|
...result,
|
|
378
437
|
logs: boundedLogs.logs,
|
|
379
438
|
logContexts: boundedLogs.logContexts,
|
|
439
|
+
logMetadata: boundedLogs.logMetadata,
|
|
440
|
+
logIds: boundedLogs.logIds,
|
|
380
441
|
stats: statsProjection.value,
|
|
381
442
|
steps: stepsProjection.values,
|
|
382
443
|
...(result.outputWarnings
|
|
@@ -408,16 +469,22 @@ function boundSettledTerminalTransportDiagnostics(
|
|
|
408
469
|
logProjection.values,
|
|
409
470
|
truncatedFields,
|
|
410
471
|
logContexts,
|
|
472
|
+
logIds,
|
|
473
|
+
logMetadata,
|
|
411
474
|
)
|
|
412
475
|
: {
|
|
413
476
|
logs: logProjection.values,
|
|
477
|
+
...(logIds ? { logIds } : {}),
|
|
414
478
|
...(logContexts?.some(Boolean) ? { logContexts } : {}),
|
|
479
|
+
...(logMetadata?.some(Boolean) ? { logMetadata } : {}),
|
|
415
480
|
};
|
|
416
481
|
return {
|
|
417
482
|
...result,
|
|
418
483
|
error: error.value,
|
|
419
484
|
logs: boundedLogs.logs,
|
|
420
485
|
logContexts: boundedLogs.logContexts,
|
|
486
|
+
logMetadata: boundedLogs.logMetadata,
|
|
487
|
+
logIds: boundedLogs.logIds,
|
|
421
488
|
stats: statsProjection.value,
|
|
422
489
|
steps: stepsProjection.values,
|
|
423
490
|
...(result.errors ? { errors: errorsProjection.values } : {}),
|
|
@@ -90,7 +90,7 @@ const DAYTONA_PUBLIC_STATUS_TRANSIENT_RETRY_PATTERN =
|
|
|
90
90
|
const DAYTONA_RUNNER_STARTUP_TRANSPORT_RETRY_PATTERN =
|
|
91
91
|
/\bDaytonaRunnerInitializationError:\s*RUNTIME_SANDBOX_START_FAILED:.*\bScheduler diagnosis:\s*runner_heartbeat_not_observed\..*"schedulerReadinessObserved":false.*"commandFound":true.*"exitCode":null.*"sessionFound":true.*"exitCodeFile":null.*"runnerStartup":\{"phase":"heartbeat_transport","outcome":"network_error","errorCode":"(?:ECONNRESET|ECONNREFUSED|ETIMEDOUT|UND_ERR_CONNECT_TIMEOUT)"/i;
|
|
92
92
|
const DAYTONA_INFRASTRUCTURE_RETRY_PATTERN =
|
|
93
|
-
/\b(?:Request failed with status code (?:408|429|500|502|503|504)|ECONNRESET|ECONNREFUSED|ETIMEDOUT|UND_ERR_CONNECT_TIMEOUT|fetch failed|socket hang up|Daytona sandbox create failed across|Daytona sandbox create did not complete|Daytona readiness baseline)\b/i;
|
|
93
|
+
/\b(?:Request failed with status code (?:408|429|500|502|503|504)|ECONNRESET|ECONNREFUSED|ETIMEDOUT|UND_ERR_CONNECT_TIMEOUT|fetch failed|socket hang up|The socket connection was closed unexpectedly|Daytona sandbox create failed across|Daytona sandbox create did not complete|Daytona readiness baseline)\b/i;
|
|
94
94
|
|
|
95
95
|
type DaytonaExecution = { exitCode: number | null; result: string };
|
|
96
96
|
export type DaytonaLookupFailure = {
|
|
@@ -86,6 +86,8 @@ export type PlaySchedulerSubmitInput = RetainedPipelineCarrier & {
|
|
|
86
86
|
* Omitted for legacy launches whose Play Run row was persisted synchronously.
|
|
87
87
|
*/
|
|
88
88
|
requiresRunCreatedProjection?: boolean;
|
|
89
|
+
/** Admission-owned producer pin. Absent keeps launch-pinned legacy logging. */
|
|
90
|
+
runtimeLogIdentity?: 'origin';
|
|
89
91
|
/** Optional inline artifact for the Node scheduler. */
|
|
90
92
|
runtimeArtifact?: unknown;
|
|
91
93
|
artifactHash: string;
|
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool-options.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import {
|
|
3
|
+
PLAY_ADMISSION_MAX_ACQUIRE_QUEUE_WAIT_MS,
|
|
4
|
+
PLAY_ADMISSION_MAX_ACTIVE_LIFECYCLES,
|
|
5
|
+
PLAY_ADMISSION_MAX_PARALLELISM,
|
|
6
|
+
} from '../admission-transport-policy';
|
|
7
|
+
import {
|
|
8
|
+
RUNTIME_SCHEDULER_CONTROL_PLANE_MAX_CLIENTS,
|
|
9
|
+
RUNTIME_SCHEDULER_SERVERLESS_IDLE_TIMEOUT_MS,
|
|
10
|
+
resolveWorkflowRuntimePostgresUrl,
|
|
11
|
+
type RuntimeSchedulerPoolOptions,
|
|
12
|
+
} from './postgres-pool';
|
|
13
|
+
|
|
14
|
+
// All queues in one worker share this single process pool. Scheduler queries
|
|
15
|
+
// are short and batched; execution concurrency belongs to Daytona/Fly slots,
|
|
16
|
+
// not to a growing set of database clients. Keeping this at two makes a
|
|
17
|
+
// horizontally scaled fleet predictable against the shared PgBouncer budget.
|
|
18
|
+
export const ABSURD_RUNTIME_POOL_MAX_CLIENTS =
|
|
19
|
+
RUNTIME_SCHEDULER_CONTROL_PLANE_MAX_CLIENTS;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Vercel Fluid invocations share a process and its scheduler pool. A single
|
|
23
|
+
* client serializes unrelated launches, reads, and critical lease lookups;
|
|
24
|
+
* one held connection can make every other request hit its acquire timeout.
|
|
25
|
+
* Use the shared two-client control-plane budget so another request can make
|
|
26
|
+
* progress while keeping each instance's PgBouncer footprint bounded.
|
|
27
|
+
*/
|
|
28
|
+
export const ABSURD_SERVERLESS_POOL_MAX_CLIENTS =
|
|
29
|
+
RUNTIME_SCHEDULER_CONTROL_PLANE_MAX_CLIENTS;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A Vercel isolate may survive long after a webhook has returned. Keep its
|
|
33
|
+
* scheduler clients only long enough to reuse them for an immediate follow-up,
|
|
34
|
+
* then return idle PgBouncer clients before the source's delayed Workpool
|
|
35
|
+
* recovery is due. The worker fleet keeps the ordinary 30-second idle lifetime.
|
|
36
|
+
*/
|
|
37
|
+
export const ABSURD_SERVERLESS_POOL_IDLE_TIMEOUT_MS =
|
|
38
|
+
RUNTIME_SCHEDULER_SERVERLESS_IDLE_TIMEOUT_MS;
|
|
39
|
+
|
|
40
|
+
// Ordinary Vercel requests share the bounded control-plane pool above. The
|
|
41
|
+
// private batch adapter is different: Workpool elects one global up-to-1,024-
|
|
42
|
+
// source collection before entering this context, so one batch request may use
|
|
43
|
+
// its larger bounded scheduler capacity without multiplying it per source.
|
|
44
|
+
// Other Workpool adapters can still overlap during rollout.
|
|
45
|
+
type ServerlessAdmissionPoolContext = {
|
|
46
|
+
maxClients: number;
|
|
47
|
+
maxAcquireQueueDepth: number;
|
|
48
|
+
maxAcquireQueueWaitMs: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const serverlessAdmissionPoolContext =
|
|
52
|
+
new AsyncLocalStorage<ServerlessAdmissionPoolContext>();
|
|
53
|
+
|
|
54
|
+
export async function withServerlessAdmissionPoolMaxClients<T>(input: {
|
|
55
|
+
maxClients: number;
|
|
56
|
+
maxAcquireQueueDepth?: number;
|
|
57
|
+
maxAcquireQueueWaitMs?: number;
|
|
58
|
+
fn: () => Promise<T>;
|
|
59
|
+
}): Promise<T> {
|
|
60
|
+
if (
|
|
61
|
+
!Number.isInteger(input.maxClients) ||
|
|
62
|
+
input.maxClients < 1 ||
|
|
63
|
+
input.maxClients > PLAY_ADMISSION_MAX_PARALLELISM
|
|
64
|
+
) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'Serverless admission pool capacity is outside the supported range.',
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const maxAcquireQueueDepth =
|
|
70
|
+
input.maxAcquireQueueDepth ?? PLAY_ADMISSION_MAX_ACTIVE_LIFECYCLES;
|
|
71
|
+
const maxAcquireQueueWaitMs =
|
|
72
|
+
input.maxAcquireQueueWaitMs ?? PLAY_ADMISSION_MAX_ACQUIRE_QUEUE_WAIT_MS;
|
|
73
|
+
if (
|
|
74
|
+
!Number.isSafeInteger(maxAcquireQueueDepth) ||
|
|
75
|
+
maxAcquireQueueDepth < 1 ||
|
|
76
|
+
maxAcquireQueueDepth > PLAY_ADMISSION_MAX_ACTIVE_LIFECYCLES
|
|
77
|
+
) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
'Serverless admission acquire queue capacity is outside the supported range.',
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
if (
|
|
83
|
+
!Number.isSafeInteger(maxAcquireQueueWaitMs) ||
|
|
84
|
+
maxAcquireQueueWaitMs < 5_000 ||
|
|
85
|
+
maxAcquireQueueWaitMs > PLAY_ADMISSION_MAX_ACQUIRE_QUEUE_WAIT_MS
|
|
86
|
+
) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
'Serverless admission acquire queue wait is outside the supported range.',
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return await serverlessAdmissionPoolContext.run(
|
|
92
|
+
{
|
|
93
|
+
maxClients: input.maxClients,
|
|
94
|
+
maxAcquireQueueDepth,
|
|
95
|
+
maxAcquireQueueWaitMs,
|
|
96
|
+
},
|
|
97
|
+
input.fn,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The private batch adapter owns this request-local scheduler pool. Reserve
|
|
103
|
+
* one client for executor-token and other critical control-plane traffic; the
|
|
104
|
+
* rest may submit the independently idempotent batch sources in parallel.
|
|
105
|
+
*/
|
|
106
|
+
export function serverlessAdmissionSubmitMaxActive(): number | null {
|
|
107
|
+
const context = serverlessAdmissionPoolContext.getStore();
|
|
108
|
+
return context === undefined ? null : Math.max(1, context.maxClients - 1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Resolve the runtime scheduler Postgres pool options for the absurd control
|
|
113
|
+
* plane. Loud failure over silent fallback: the absurd worker and scheduler
|
|
114
|
+
* only run under Node where `WORKFLOW_RUNTIME_POSTGRES` is configured.
|
|
115
|
+
*/
|
|
116
|
+
export function resolveAbsurdPoolOptions(
|
|
117
|
+
explicitUrl?: string | null,
|
|
118
|
+
): RuntimeSchedulerPoolOptions {
|
|
119
|
+
const url = explicitUrl?.trim() || resolveWorkflowRuntimePostgresUrl();
|
|
120
|
+
if (!url) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
'absurd scheduler backend requires WORKFLOW_RUNTIME_POSTGRES (runtime ' +
|
|
123
|
+
'scheduler Postgres URL). Refusing to fall back to local execution.',
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
const serverless = process.env.VERCEL?.trim();
|
|
127
|
+
const context = serverlessAdmissionPoolContext.getStore();
|
|
128
|
+
return {
|
|
129
|
+
url,
|
|
130
|
+
applicationName: 'deepline-absurd-runtime',
|
|
131
|
+
maxClients:
|
|
132
|
+
serverless || context !== undefined
|
|
133
|
+
? (context?.maxClients ?? ABSURD_SERVERLESS_POOL_MAX_CLIENTS)
|
|
134
|
+
: ABSURD_RUNTIME_POOL_MAX_CLIENTS,
|
|
135
|
+
...(serverless || context !== undefined
|
|
136
|
+
? { idleTimeoutMs: ABSURD_SERVERLESS_POOL_IDLE_TIMEOUT_MS }
|
|
137
|
+
: {}),
|
|
138
|
+
...(context
|
|
139
|
+
? {
|
|
140
|
+
maxAcquireQueueDepth: context.maxAcquireQueueDepth,
|
|
141
|
+
maxAcquireQueueWaitMs: context.maxAcquireQueueWaitMs,
|
|
142
|
+
}
|
|
143
|
+
: {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts
CHANGED
|
@@ -3040,8 +3040,14 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3040
3040
|
});
|
|
3041
3041
|
}
|
|
3042
3042
|
|
|
3043
|
-
//
|
|
3044
|
-
//
|
|
3043
|
+
// Terminal step errors and failed-map settled counts ride the existing
|
|
3044
|
+
// terminal outbox row. They no longer need a progress write immediately
|
|
3045
|
+
// ahead of the terminal in the same ordered run stream.
|
|
3046
|
+
const observedTerminalProgressEvents =
|
|
3047
|
+
progressReporter.collectTerminalFailureProgressEvents?.() ?? [];
|
|
3048
|
+
if (observedTerminalProgressEvents.length > 0) {
|
|
3049
|
+
progressReporter.markTerminalFailureProgressPersisted?.();
|
|
3050
|
+
}
|
|
3045
3051
|
const failedTerminalProgressEvents =
|
|
3046
3052
|
runnerResult.status === 'failed'
|
|
3047
3053
|
? await collectFailedTerminalSettledProgressEvents({
|
|
@@ -3059,8 +3065,14 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3059
3065
|
...options,
|
|
3060
3066
|
terminalLogOutbox: input.fromDetachedRunner ? 'ctx_log_tail' : 'omit',
|
|
3061
3067
|
sandboxCrashDiagnostic,
|
|
3062
|
-
...(
|
|
3063
|
-
|
|
3068
|
+
...(observedTerminalProgressEvents.length > 0 ||
|
|
3069
|
+
failedTerminalProgressEvents.length > 0
|
|
3070
|
+
? {
|
|
3071
|
+
terminalProgressEvents: [
|
|
3072
|
+
...observedTerminalProgressEvents,
|
|
3073
|
+
...failedTerminalProgressEvents,
|
|
3074
|
+
],
|
|
3075
|
+
}
|
|
3064
3076
|
: {}),
|
|
3065
3077
|
},
|
|
3066
3078
|
),
|
|
@@ -4463,7 +4475,6 @@ function createAbsurdWorkerTerminalProjectionAdapter(input: {
|
|
|
4463
4475
|
);
|
|
4464
4476
|
});
|
|
4465
4477
|
};
|
|
4466
|
-
let projectionStartedAtMs: number | undefined;
|
|
4467
4478
|
return createPlayRunAttemptWorkerTerminalProjection({
|
|
4468
4479
|
async observeFenceLost() {
|
|
4469
4480
|
// A lost fence means this attempt is dead, which a cancelled run is the
|
|
@@ -4479,7 +4490,6 @@ function createAbsurdWorkerTerminalProjectionAdapter(input: {
|
|
|
4479
4490
|
});
|
|
4480
4491
|
},
|
|
4481
4492
|
async reconcileTerminalTruth() {
|
|
4482
|
-
projectionStartedAtMs ??= Date.now();
|
|
4483
4493
|
// ADR 0016 rule 3: detached Daytona runs may provide no live events, so
|
|
4484
4494
|
// fold stored docflow/runtime-sheet facts into progress after truth wins.
|
|
4485
4495
|
await reconcileTerminalTruthIntoReporter({
|
|
@@ -4564,9 +4574,7 @@ function createAbsurdWorkerTerminalProjectionAdapter(input: {
|
|
|
4564
4574
|
runId: input.runId,
|
|
4565
4575
|
options: input.options,
|
|
4566
4576
|
trigger: 'committed_terminal',
|
|
4567
|
-
|
|
4568
|
-
? {}
|
|
4569
|
-
: { projectionStartedAtMs }),
|
|
4577
|
+
projectionStartedAtMs: Date.now(),
|
|
4570
4578
|
});
|
|
4571
4579
|
},
|
|
4572
4580
|
});
|