deepline 0.3.409 → 0.3.411
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/agent-runtime.ts +18 -1
- package/dist/bundling-sources/sdk/src/client.ts +206 -333
- package/dist/bundling-sources/sdk/src/compat.ts +45 -2
- package/dist/bundling-sources/sdk/src/db/query.ts +9 -10
- package/dist/bundling-sources/sdk/src/http.ts +38 -20
- package/dist/bundling-sources/sdk/src/index.ts +4 -5
- package/dist/bundling-sources/sdk/src/play.ts +10 -10
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +6 -4
- package/dist/bundling-sources/sdk/src/plays/check-local-play-graph.ts +114 -0
- package/dist/bundling-sources/sdk/src/plays/client.ts +431 -0
- package/dist/bundling-sources/sdk/src/plays/local-play-execution.ts +2 -2
- package/dist/bundling-sources/sdk/src/plays/run-request.ts +106 -16
- package/dist/bundling-sources/sdk/src/release.ts +13 -7
- package/dist/bundling-sources/sdk/src/runs/read-errors.ts +8 -0
- package/dist/bundling-sources/sdk/src/runs/watch-polling.ts +124 -13
- package/dist/bundling-sources/sdk/src/tool-calls.ts +108 -19
- package/dist/bundling-sources/sdk/src/types.ts +18 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/execute-retry-contract.ts +37 -0
- package/dist/bundling-sources/shared_libs/integration-contracts/package.json +3 -0
- package/dist/bundling-sources/shared_libs/monitors/package.json +1 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +3 -1
- package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +277 -76
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/dataset-row-input.ts +124 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +6 -62
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-tool-identity.ts +67 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +64 -6
- package/dist/bundling-sources/shared_libs/play-runtime/freshness-receipt-execution.ts +1 -5
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-artifact-runtime-contract.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-http-request.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/query-result-dataset.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +26 -16
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-heartbeat.ts +36 -11
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +35 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +21 -6
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +11 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +85 -20
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +71 -13
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-execution-queries.ts +100 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +9 -5
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +337 -146
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +26 -12
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +3 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +425 -102
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +181 -124
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-worker-wake.ts +152 -0
- package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +5 -3
- package/dist/bundling-sources/shared_libs/play-runtime/tool-cache-policy.ts +31 -0
- package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +10 -0
- package/dist/bundling-sources/shared_libs/plays/ambiguous-write-error.ts +25 -0
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +63 -68
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +129 -63
- package/dist/bundling-sources/shared_libs/plays/contracts.ts +14 -0
- package/dist/bundling-sources/shared_libs/plays/enrich-play-compiler.ts +58 -16
- package/dist/bundling-sources/shared_libs/plays/fetch-http-error.ts +50 -0
- package/dist/bundling-sources/shared_libs/plays/source-authoring-edition.ts +351 -0
- package/dist/bundling-sources/shared_libs/plays/tool-list-getter-mode.ts +9 -0
- package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
- package/dist/cli/auth-M7TBLW55.js +40 -0
- package/dist/cli/{auth-5HIIACF7.mjs → auth-YD6ZTMB2.mjs} +6 -6
- package/dist/cli/{billing-4275N7FL.js → billing-2L3MOB42.js} +84 -84
- package/dist/cli/{billing-EVZ3ZWKC.mjs → billing-ZT46GV4C.mjs} +8 -8
- package/dist/cli/{chunk-ZAAKSJAS.js → chunk-27GJKC5Q.js} +17 -10
- package/dist/cli/{chunk-UHNDVD3P.js → chunk-2H4EY7KH.js} +100 -41
- package/dist/cli/{chunk-GAICVLKL.js → chunk-2NI6DHN7.js} +2 -2
- package/dist/cli/{chunk-JGHG4NBA.js → chunk-2WUY3VNK.js} +19 -4
- package/dist/cli/{chunk-FHPCKULR.mjs → chunk-4BA6ATHA.mjs} +2 -2
- package/dist/cli/{chunk-RTCDW2GU.js → chunk-4O4WNFFC.js} +170 -49
- package/dist/cli/{chunk-OSDXE27V.mjs → chunk-4PG4ARL2.mjs} +17 -10
- package/dist/cli/{chunk-AU4OFDFX.js → chunk-5IGDNBG7.js} +26 -26
- package/dist/cli/{chunk-WYQO2CBS.mjs → chunk-5LRWWMRV.mjs} +149 -28
- package/dist/cli/{chunk-PMVFAYL7.mjs → chunk-63ILLN5H.mjs} +2 -2
- package/dist/cli/chunk-6AUE6JXY.js +35 -0
- package/dist/cli/chunk-7DSMMCXP.js +501 -0
- package/dist/cli/{chunk-6BJK4EJ3.mjs → chunk-AARWVK4C.mjs} +2132 -65
- package/dist/cli/{chunk-FERRDNMO.js → chunk-AD47BXN2.js} +5 -5
- package/dist/cli/{chunk-J6DCKJNM.mjs → chunk-BJV3VSKE.mjs} +16 -1
- package/dist/cli/{chunk-S6R3OX7B.js → chunk-E4CABWXL.js} +25 -2
- package/dist/cli/{chunk-NXGCO4JB.mjs → chunk-E4IXDAZI.mjs} +5 -0
- package/dist/cli/{chunk-BEVLCKXG.mjs → chunk-E4KBNNNB.mjs} +1 -1
- package/dist/cli/{chunk-2PRO2JTX.mjs → chunk-E52TKKVI.mjs} +36 -284
- package/dist/cli/chunk-FR2ILQ4G.mjs +8 -0
- package/dist/cli/{chunk-2GI3QD3L.js → chunk-FRVPOXGB.js} +644 -330
- package/dist/cli/chunk-G43JLBDE.mjs +501 -0
- package/dist/cli/{chunk-BZAMOCPA.mjs → chunk-IMZ56EOH.mjs} +3 -3
- package/dist/cli/chunk-IPGV6VFA.mjs +6084 -0
- package/dist/cli/{chunk-IT3XBJQR.mjs → chunk-IR3AKJAY.mjs} +330 -625
- package/dist/cli/chunk-J33TSWO5.js +8 -0
- package/dist/cli/chunk-JQMZUWNM.mjs +35 -0
- package/dist/cli/chunk-JYHSEGRM.js +6084 -0
- package/dist/cli/{chunk-JI2B4RZP.mjs → chunk-KCC3FKIW.mjs} +71 -12
- package/dist/cli/{chunk-6IKARAYD.mjs → chunk-L2VKAASU.mjs} +23 -0
- package/dist/cli/{chunk-O3VSXP2F.js → chunk-LWBM5FFL.js} +50 -50
- package/dist/cli/{chunk-VWBTTJYQ.mjs → chunk-M6OASCVL.mjs} +6 -3
- package/dist/cli/{chunk-YHPYUZZX.mjs → chunk-MAMVGOSC.mjs} +1 -1
- package/dist/cli/{chunk-Q2E4E4FJ.js → chunk-NPBJI7RE.js} +8 -8
- package/dist/cli/chunk-NQWIZ5PZ.js +313 -0
- package/dist/cli/{chunk-HQXL5526.mjs → chunk-NUX2QHNC.mjs} +1 -1
- package/dist/cli/{chunk-TQNHMWUR.mjs → chunk-OGSXENOF.mjs} +5 -2
- package/dist/cli/{chunk-SEFMGO3Z.js → chunk-OQQOXSYA.js} +2184 -117
- package/dist/cli/{chunk-FJCIUF34.js → chunk-OZSC6CEW.js} +128 -376
- package/dist/cli/{chunk-NZSF57UO.mjs → chunk-PO2VU6WV.mjs} +2 -2
- package/dist/cli/{chunk-7P5AA3SN.js → chunk-PPDBRJRW.js} +6 -1
- package/dist/cli/{chunk-ILHRA7AD.js → chunk-QADCFSGH.js} +7 -7
- package/dist/cli/{chunk-N44JHMKY.mjs → chunk-RFES6Q2J.mjs} +452 -138
- package/dist/cli/{chunk-DEC3JECC.js → chunk-RMINBDYY.js} +5 -2
- package/dist/cli/{chunk-WLOCMJWV.js → chunk-TPFD4F5S.js} +426 -721
- package/dist/cli/{chunk-V76R6HMV.js → chunk-U5AQKE3T.js} +1029 -806
- package/dist/cli/{chunk-PBZYY7VZ.mjs → chunk-UAEVKAUR.mjs} +734 -511
- package/dist/cli/{chunk-WHG43Z67.js → chunk-VGHWJL4W.js} +11 -8
- package/dist/cli/chunk-VKKVSFRD.js +62 -0
- package/dist/cli/{chunk-GSK6NHVM.js → chunk-WU4U6VSB.js} +5 -5
- package/dist/cli/chunk-XAB47ZRV.mjs +313 -0
- package/dist/cli/{chunk-JRAVVJ3T.mjs → chunk-XJD6LZCO.mjs} +2 -2
- package/dist/cli/chunk-ZCALLYF6.mjs +62 -0
- package/dist/cli/{chunk-YD7B53RW.js → chunk-ZHWBU36H.js} +12 -12
- package/dist/cli/{csv-A2MP6EFV.mjs → csv-BKNRRW7D.mjs} +5 -5
- package/dist/cli/{csv-BBOTCGQY.js → csv-SVDP2EU7.js} +14 -14
- package/dist/cli/{db-3W5DMTUX.mjs → db-LU4KLRM6.mjs} +15 -20
- package/dist/cli/{db-G4CODDCA.js → db-OQ6S7TTZ.js} +42 -47
- package/dist/cli/{describe-PQTQ5B6F.js → describe-45TGETKR.js} +27 -22
- package/dist/cli/{describe-XYJ2ZT4M.mjs → describe-U4KOGDRA.mjs} +20 -15
- package/dist/cli/describe-core.d.mts +2 -2
- package/dist/cli/describe-core.d.ts +2 -2
- package/dist/cli/describe-core.js +6 -6
- package/dist/cli/describe-core.mjs +5 -5
- package/dist/cli/{executions-UR67CA5H.mjs → executions-2GAAUXLA.mjs} +8 -8
- package/dist/cli/{executions-TLANVR7Y.js → executions-VZN56VRC.js} +10 -10
- package/dist/cli/{feedback-6C2YTRJL.js → feedback-NS76B5GU.js} +13 -9
- package/dist/cli/{feedback-WHCMGEIL.mjs → feedback-XW5IWA5R.mjs} +11 -7
- package/dist/cli/{git-GWLB6VSA.mjs → git-CLI66XP6.mjs} +6 -6
- package/dist/cli/git-VGYRGFEN.js +24 -0
- package/dist/cli/index.js +236 -348
- package/dist/cli/index.mjs +162 -274
- package/dist/cli/{legacy-noops-ZUFA7RWI.js → legacy-noops-HCFB3ZOV.js} +9 -9
- package/dist/cli/{legacy-noops-KF4XIFEF.mjs → legacy-noops-ODDOMLBL.mjs} +6 -6
- package/dist/cli/{monitors-TB3K2IVE.js → monitors-7WXQ7JFT.js} +94 -94
- package/dist/cli/{monitors-6UOIDIMB.mjs → monitors-ZXX456TE.mjs} +8 -8
- package/dist/cli/{org-CKWMBPIR.js → org-YLX5PHBQ.js} +68 -68
- package/dist/cli/{org-WGHHMVDZ.mjs → org-YUN3TLNP.mjs} +8 -8
- package/dist/cli/{play-LYPAXCLD.mjs → play-LL73A7EP.mjs} +533 -98
- package/dist/cli/{play-N2B3KAVS.js → play-YGOXL52D.js} +1067 -632
- package/dist/cli/{providers-6DI5BVZJ.mjs → providers-35QSAUHL.mjs} +8 -8
- package/dist/cli/{providers-UR42MD6Z.js → providers-RHCIU2PX.js} +11 -11
- package/dist/cli/{quickstart-MNA2S6PO.mjs → quickstart-6BN3LCZH.mjs} +5 -5
- package/dist/cli/{quickstart-FCJG4XGB.js → quickstart-ORMM4NRK.js} +7 -7
- package/dist/cli/search-EWDMUPHR.js +30 -0
- package/dist/cli/{search-VPPYUJ2M.mjs → search-GAERWLSE.mjs} +9 -9
- package/dist/cli/{secrets-QOSMVO36.js → secrets-3AFCTGT7.js} +17 -17
- package/dist/cli/{secrets-DRI4W7Z5.mjs → secrets-FCL5PALY.mjs} +8 -8
- package/dist/cli/sessions-3OEHEQG7.js +16 -0
- package/dist/cli/{sessions-DQNUKP43.mjs → sessions-RSSL7I7O.mjs} +6 -6
- package/dist/cli/{settings-DWDK3Y2R.mjs → settings-GE4NRE7Y.mjs} +12 -12
- package/dist/cli/{settings-JUGGCOPS.js → settings-RX5K4I7H.js} +79 -79
- package/dist/cli/{setup-AWBHNYXK.js → setup-N3ZNAEL5.js} +45 -44
- package/dist/cli/{setup-D5DWVNY4.mjs → setup-X3RXGG4F.mjs} +11 -10
- package/dist/cli/{skills-YV2XR35J.mjs → skills-5JEAJBDE.mjs} +7 -7
- package/dist/cli/skills-VAAQVEQC.js +29 -0
- package/dist/cli/tools-BYYOT2DU.js +44 -0
- package/dist/cli/{tools-VFJYHNV2.mjs → tools-JOKUWEBZ.mjs} +19 -14
- package/dist/cli/update-36G4ZD7B.js +31 -0
- package/dist/cli/{update-IM6VOTGL.mjs → update-UBHEVFR3.mjs} +11 -9
- package/dist/cli/{workflow-26URBWPV.mjs → workflow-FR6EXAXF.mjs} +44 -20
- package/dist/cli/{workflow-3BS6U6SL.js → workflow-SZAVOHN6.js} +54 -30
- package/dist/{client-BfInrZPB.d.mts → client-74k4IPh6.d.mts} +135 -54
- package/dist/{client-BMjJFpan.d.ts → client-C1IK1f8c.d.ts} +135 -54
- package/dist/{compiler-manifest-Ycx-hoAr.d.mts → compiler-manifest-lzWpbV3w.d.mts} +83 -66
- package/dist/{compiler-manifest-Ycx-hoAr.d.ts → compiler-manifest-lzWpbV3w.d.ts} +83 -66
- package/dist/{index-CZXgiN3E.d.mts → index-C8Cy-YTm.d.ts} +5 -1
- package/dist/{index-NPG5pqxQ.d.ts → index-CtNK-0nI.d.mts} +5 -1
- package/dist/index.d.mts +47 -9
- package/dist/index.d.ts +47 -9
- package/dist/index.js +17 -14
- package/dist/index.mjs +13 -10
- package/dist/install-integrity.json +118 -102
- package/dist/plays/bundle-play-file.d.mts +3 -3
- package/dist/plays/bundle-play-file.d.ts +3 -3
- package/dist/plays/bundle-play-file.mjs +5 -4
- package/dist/plays/csv-data-input.js +3 -3
- package/dist/plays/csv-data-input.mjs +2 -2
- package/dist/plays/play-description.d.mts +2 -2
- package/dist/plays/play-description.d.ts +2 -2
- package/dist/plays/run-request.d.mts +2 -2
- package/dist/plays/run-request.d.ts +2 -2
- package/dist/plays/run-request.js +11 -3
- package/dist/plays/run-request.mjs +10 -2
- package/dist/release.d.mts +15 -6
- package/dist/release.d.ts +15 -6
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/package.json +2 -2
- package/dist/cli/auth-F6BX32XZ.js +0 -40
- package/dist/cli/chunk-264PC2RN.mjs +0 -83
- package/dist/cli/chunk-44ZTYHMQ.mjs +0 -155
- package/dist/cli/chunk-53HN7WZN.js +0 -392
- package/dist/cli/chunk-7AALNGTA.mjs +0 -392
- package/dist/cli/chunk-ALD4COBH.js +0 -155
- package/dist/cli/chunk-CLJGSOVM.mjs +0 -1716
- package/dist/cli/chunk-WNUR6VP5.js +0 -83
- package/dist/cli/chunk-Z4VNJOF7.js +0 -1716
- package/dist/cli/git-VQFF6D7C.js +0 -24
- package/dist/cli/search-NCEEONMQ.js +0 -30
- package/dist/cli/sessions-3WYKQABW.js +0 -16
- package/dist/cli/skills-AKPAJVSO.js +0 -29
- package/dist/cli/tools-RBKEK6PM.js +0 -39
- package/dist/cli/update-VFNUBLDA.js +0 -29
|
@@ -59,6 +59,8 @@ export interface RunnerHeartbeatLoopOptions {
|
|
|
59
59
|
executorToken: string;
|
|
60
60
|
runId: string;
|
|
61
61
|
leaseSeconds: number;
|
|
62
|
+
/** Keep managed startup heartbeats active until the scheduler parks the attempt. */
|
|
63
|
+
waitForSchedulerPark?: boolean;
|
|
62
64
|
/**
|
|
63
65
|
* Invoked once when the loop decides the runner must self-terminate (terminal
|
|
64
66
|
* cancellation channel, or gateway unreachable past the lease window). The
|
|
@@ -109,6 +111,8 @@ export const RUNNER_HEARTBEAT_REQUEST_TIMEOUT_MS = 10_000;
|
|
|
109
111
|
// The detached startup deadline is shorter than the normal 40s cadence.
|
|
110
112
|
// Retry initial transport failures while customer execution remains fenced.
|
|
111
113
|
const RUNNER_STARTUP_HEARTBEAT_INTERVAL_MS = 1_000;
|
|
114
|
+
const RUNNER_PARK_ACK_INTERVAL_MS = 100;
|
|
115
|
+
const RUNNER_PARK_ACK_FAST_WINDOW_MS = 1_000;
|
|
112
116
|
|
|
113
117
|
export async function sendRunnerHeartbeat(
|
|
114
118
|
input: {
|
|
@@ -324,6 +328,8 @@ export function startRunnerHeartbeatLoop(
|
|
|
324
328
|
let heartbeatAttempt = 0;
|
|
325
329
|
let lastSuccessAt = now();
|
|
326
330
|
let handle: { unref?: () => void } | null = null;
|
|
331
|
+
let intervalMs = Math.min(cadenceMs, RUNNER_STARTUP_HEARTBEAT_INTERVAL_MS);
|
|
332
|
+
let fastParkAckUntil: number | null = null;
|
|
327
333
|
let resolveFirstHeartbeat: (() => void) | null = null;
|
|
328
334
|
const firstHeartbeat = new Promise<void>((resolve) => {
|
|
329
335
|
resolveFirstHeartbeat = resolve;
|
|
@@ -333,6 +339,15 @@ export function startRunnerHeartbeatLoop(
|
|
|
333
339
|
resolveExecutionAcknowledged = resolve;
|
|
334
340
|
});
|
|
335
341
|
|
|
342
|
+
const setCadence = (ms: number) => {
|
|
343
|
+
if (!handle || intervalMs !== ms) {
|
|
344
|
+
if (handle) clearIntervalImpl(handle);
|
|
345
|
+
intervalMs = ms;
|
|
346
|
+
handle = setIntervalImpl(tick, ms);
|
|
347
|
+
}
|
|
348
|
+
if (!resolveFirstHeartbeat) handle.unref?.();
|
|
349
|
+
};
|
|
350
|
+
|
|
336
351
|
const stopLoop = () => {
|
|
337
352
|
if (stopped) return;
|
|
338
353
|
stopped = true;
|
|
@@ -359,6 +374,12 @@ export function startRunnerHeartbeatLoop(
|
|
|
359
374
|
leaseSeconds: options.leaseSeconds,
|
|
360
375
|
attempt: heartbeatAttempt,
|
|
361
376
|
})
|
|
377
|
+
.finally(() => {
|
|
378
|
+
// A caller may request the park acknowledgement as soon as the first
|
|
379
|
+
// heartbeat resolves. Release this completed transport before exposing
|
|
380
|
+
// that fence so the immediate request is not mistaken for an overlap.
|
|
381
|
+
inFlight = false;
|
|
382
|
+
})
|
|
362
383
|
.then((result) => {
|
|
363
384
|
if (stopped) return;
|
|
364
385
|
if (result.ok === false) {
|
|
@@ -369,10 +390,7 @@ export function startRunnerHeartbeatLoop(
|
|
|
369
390
|
if (resolveFirstHeartbeat) {
|
|
370
391
|
resolveFirstHeartbeat();
|
|
371
392
|
resolveFirstHeartbeat = null;
|
|
372
|
-
|
|
373
|
-
if (handle) clearIntervalImpl(handle);
|
|
374
|
-
handle = setIntervalImpl(tick, cadenceMs);
|
|
375
|
-
handle.unref?.();
|
|
393
|
+
fastParkAckUntil = now() + RUNNER_PARK_ACK_FAST_WINDOW_MS;
|
|
376
394
|
}
|
|
377
395
|
if (
|
|
378
396
|
result.schedulerStatus === 'waiting' &&
|
|
@@ -381,6 +399,16 @@ export function startRunnerHeartbeatLoop(
|
|
|
381
399
|
resolveExecutionAcknowledged();
|
|
382
400
|
resolveExecutionAcknowledged = null;
|
|
383
401
|
}
|
|
402
|
+
// One loop owns the managed startup handshake. A healthy, unparked
|
|
403
|
+
// attempt briefly uses the fast cadence; slow/legacy acknowledgements
|
|
404
|
+
// return to startup pacing, and confirmed parking restores lease pacing.
|
|
405
|
+
setCadence(
|
|
406
|
+
options.waitForSchedulerPark && resolveExecutionAcknowledged
|
|
407
|
+
? fastParkAckUntil !== null && now() < fastParkAckUntil
|
|
408
|
+
? RUNNER_PARK_ACK_INTERVAL_MS
|
|
409
|
+
: RUNNER_STARTUP_HEARTBEAT_INTERVAL_MS
|
|
410
|
+
: cadenceMs,
|
|
411
|
+
);
|
|
384
412
|
})
|
|
385
413
|
.catch((error) => {
|
|
386
414
|
if (stopped) return;
|
|
@@ -395,24 +423,21 @@ export function startRunnerHeartbeatLoop(
|
|
|
395
423
|
});
|
|
396
424
|
return;
|
|
397
425
|
}
|
|
426
|
+
if (options.waitForSchedulerPark && resolveExecutionAcknowledged) {
|
|
427
|
+
setCadence(RUNNER_STARTUP_HEARTBEAT_INTERVAL_MS);
|
|
428
|
+
}
|
|
398
429
|
warn('heartbeat_failed_retrying', {
|
|
399
430
|
runId: options.runId,
|
|
400
431
|
sinceMs,
|
|
401
432
|
leaseMs,
|
|
402
433
|
error: message,
|
|
403
434
|
});
|
|
404
|
-
})
|
|
405
|
-
.finally(() => {
|
|
406
|
-
inFlight = false;
|
|
407
435
|
});
|
|
408
436
|
};
|
|
409
437
|
|
|
410
438
|
// Keep this timer referenced until the first accepted heartbeat: a pending
|
|
411
439
|
// Promise alone does not keep Node alive after an initial transport failure.
|
|
412
|
-
|
|
413
|
-
tick,
|
|
414
|
-
Math.min(cadenceMs, RUNNER_STARTUP_HEARTBEAT_INTERVAL_MS),
|
|
415
|
-
);
|
|
440
|
+
setCadence(intervalMs);
|
|
416
441
|
// Fire one immediately so a cancel that landed before the first interval is
|
|
417
442
|
// observed within a cadence, not a full lease window.
|
|
418
443
|
tick();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
1
2
|
import {
|
|
2
3
|
RUNNER_TERMINAL_CHECKPOINT_DISPOSITION,
|
|
3
4
|
type PlayRunnerEvent,
|
|
@@ -551,6 +552,8 @@ export interface PushRunnerTerminalOptions {
|
|
|
551
552
|
result: PlayRunnerResult | PlayRunnerTerminalTransportResult;
|
|
552
553
|
finalProgressEvents?: PlayRunnerEvent[];
|
|
553
554
|
finalProgressLogOffset?: number;
|
|
555
|
+
/** Existing per-invocation completion marker, shared with crash recovery. */
|
|
556
|
+
runtimeCompletedPath?: string;
|
|
554
557
|
/** Injectable for tests. Defaults to a bearer POST to the gateway. */
|
|
555
558
|
fetchImpl?: typeof fetch;
|
|
556
559
|
sleepImpl?: (ms: number) => Promise<void>;
|
|
@@ -722,6 +725,38 @@ export async function pushRunnerTerminal(
|
|
|
722
725
|
if (response.ok) {
|
|
723
726
|
await response.text().catch(() => '');
|
|
724
727
|
reportTransport('ok', { status: response.status });
|
|
728
|
+
if (options.runtimeCompletedPath) {
|
|
729
|
+
try {
|
|
730
|
+
const marker: unknown = JSON.parse(
|
|
731
|
+
readFileSync(options.runtimeCompletedPath, 'utf8'),
|
|
732
|
+
);
|
|
733
|
+
if (
|
|
734
|
+
!marker ||
|
|
735
|
+
typeof marker !== 'object' ||
|
|
736
|
+
Array.isArray(marker) ||
|
|
737
|
+
!('completed' in marker) ||
|
|
738
|
+
marker.completed !== true
|
|
739
|
+
) {
|
|
740
|
+
throw new Error('Invalid runtime completion marker');
|
|
741
|
+
}
|
|
742
|
+
// Preserve the original completion timestamp: the watchdog's
|
|
743
|
+
// settlement grace still starts when customer execution ended.
|
|
744
|
+
writeFileSync(
|
|
745
|
+
options.runtimeCompletedPath,
|
|
746
|
+
JSON.stringify({
|
|
747
|
+
...marker,
|
|
748
|
+
terminalAcknowledgedRunId: options.runId,
|
|
749
|
+
}),
|
|
750
|
+
'utf8',
|
|
751
|
+
);
|
|
752
|
+
} catch {
|
|
753
|
+
// The terminal is already durable. Failure to record this local
|
|
754
|
+
// handoff retains the existing first-write-wins epilogue POST.
|
|
755
|
+
warn('terminal_acknowledgement_marker_unavailable', {
|
|
756
|
+
runId: options.runId,
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
}
|
|
725
760
|
return true;
|
|
726
761
|
}
|
|
727
762
|
const body = await response.text().catch(() => '');
|
|
@@ -361,6 +361,10 @@ function deadline(timeoutMs: number, signal?: AbortSignal) {
|
|
|
361
361
|
export function createDaytonaLaunchClient(
|
|
362
362
|
options: DaytonaClientOptions,
|
|
363
363
|
cancellation?: AbortSignal,
|
|
364
|
+
onCreateStage?: (
|
|
365
|
+
stage: 'create:response' | 'create:started',
|
|
366
|
+
timing: Record<string, unknown>,
|
|
367
|
+
) => void,
|
|
364
368
|
) {
|
|
365
369
|
if (!options.apiKey?.trim())
|
|
366
370
|
throw new Error('Daytona launch requires the configured API key.');
|
|
@@ -421,6 +425,7 @@ export function createDaytonaLaunchClient(
|
|
|
421
425
|
}),
|
|
422
426
|
);
|
|
423
427
|
sent = true;
|
|
428
|
+
const requestStartedAt = performance.now();
|
|
424
429
|
const response = await api.createSandbox(
|
|
425
430
|
{
|
|
426
431
|
name: params.name,
|
|
@@ -447,9 +452,25 @@ export function createDaytonaLaunchClient(
|
|
|
447
452
|
{ timeout: timeoutMs },
|
|
448
453
|
);
|
|
449
454
|
data = response.data;
|
|
455
|
+
try {
|
|
456
|
+
onCreateStage?.('create:response', {
|
|
457
|
+
createRequestMs: performance.now() - requestStartedAt,
|
|
458
|
+
initialState: daytonaSandboxStateForLog(data.state),
|
|
459
|
+
});
|
|
460
|
+
} catch {
|
|
461
|
+
// An advisory observer cannot select provider recovery or skip readiness.
|
|
462
|
+
}
|
|
450
463
|
const sandbox = makeSandbox(data, () => phase.signal);
|
|
451
464
|
waiting = sandbox;
|
|
465
|
+
const readyStartedAt = performance.now();
|
|
452
466
|
await sandbox.waitUntilStarted(options.timeout ?? 60);
|
|
467
|
+
try {
|
|
468
|
+
onCreateStage?.('create:started', {
|
|
469
|
+
providerReadyWaitMs: performance.now() - readyStartedAt,
|
|
470
|
+
});
|
|
471
|
+
} catch {
|
|
472
|
+
// Provider success remains authoritative if its observer fails.
|
|
473
|
+
}
|
|
453
474
|
// Future phases own fresh deadlines; none inherits this create scope.
|
|
454
475
|
return makeSandbox(
|
|
455
476
|
{
|
|
@@ -157,9 +157,10 @@ function nodeMaterializePayloadCommand(input: {
|
|
|
157
157
|
* 2. push it — or a synthesized crash failure naming the exit code — to the
|
|
158
158
|
* gateway's `runner_terminal` action.
|
|
159
159
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
160
|
+
* A successful in-runner push records its acknowledgement in the existing
|
|
161
|
+
* per-invocation completion marker. Only that positive acknowledgement skips
|
|
162
|
+
* the epilogue POST. Older runners and missing/ambiguous acknowledgements
|
|
163
|
+
* retain the gateway's first-write-wins recovery.
|
|
163
164
|
*
|
|
164
165
|
* Exported (with the builder) for the unit test that executes the script
|
|
165
166
|
* against a real local HTTP server.
|
|
@@ -178,6 +179,7 @@ const runtimeLimitMarkerPath = process.argv[5] || '';
|
|
|
178
179
|
const oomKillBaselinePath = process.argv[6] || '';
|
|
179
180
|
const memoryEventsPath = process.argv[7] || '/sys/fs/cgroup/memory.events';
|
|
180
181
|
const terminationDiagnosticPath = process.argv[8] || '';
|
|
182
|
+
const runtimeCompletedPath = process.argv[9] || '';
|
|
181
183
|
const exitCode = Number.isFinite(exitCodeRaw) ? exitCodeRaw : null;
|
|
182
184
|
const MAX_OUTPUT_BYTES = ${DAYTONA_CRASH_PUSHER_OUTPUT_TAIL_MAX_BYTES};
|
|
183
185
|
const MAX_POST_TERMINAL_DIAGNOSTIC_BYTES = ${RUNNER_POST_TERMINAL_DIAGNOSTIC_MAX_BYTES};
|
|
@@ -360,6 +362,19 @@ async function main() {
|
|
|
360
362
|
writeDiagnostic('[crash-terminal] no push config; skipping');
|
|
361
363
|
return;
|
|
362
364
|
}
|
|
365
|
+
if (runtimeCompletedPath) {
|
|
366
|
+
try {
|
|
367
|
+
const marker = JSON.parse(fs.readFileSync(runtimeCompletedPath, 'utf8'));
|
|
368
|
+
if (
|
|
369
|
+
marker &&
|
|
370
|
+
marker.completed === true &&
|
|
371
|
+
marker.terminalAcknowledgedRunId === push.runId
|
|
372
|
+
) {
|
|
373
|
+
writeDiagnostic('[crash-terminal] terminal already acknowledged; skipping');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
} catch {}
|
|
377
|
+
}
|
|
363
378
|
const parsedResultEvent = readResultEventFromOutput();
|
|
364
379
|
const parsedResult = parsedResultEvent && parsedResultEvent.result;
|
|
365
380
|
// Exit codes are authored-program output too: a play may intentionally call
|
|
@@ -725,14 +740,14 @@ export async function stageRunnerPayload(input: {
|
|
|
725
740
|
crashPusherPath,
|
|
726
741
|
})} && DEEPLINE_PLAY_RUNNER_RUNTIME_STARTED_PATH=${shellQuote(runtimeStartedPath)} DEEPLINE_PLAY_RUNNER_RUNTIME_COMPLETED_PATH=${shellQuote(runtimeCompletedPath)} DEEPLINE_PLAY_RUNNER_PROGRESS_EVENT_PATH=${shellQuote(progressEventPath)} DEEPLINE_PLAY_RUNNER_STARTUP_DIAGNOSTIC_PATH=${shellQuote(startupDiagnosticPath)} DEEPLINE_PLAY_RUNNER_STDOUT_EVENT_MODE=compact UV_THREADPOOL_SIZE=${PLAY_RUNNER_UV_THREADPOOL_SIZE} ${runtimeReliabilityEnv}${runnerTraceEnv}${sandboxTargetEnv}${watchedRunnerCommand}`;
|
|
727
742
|
// Crash-containment epilogue: runs UNCONDITIONALLY after the runner exits and
|
|
728
|
-
// pushes
|
|
743
|
+
// pushes an unacknowledged parsed (or synthesized) terminal so the parked
|
|
729
744
|
// worker wakes within seconds of ANY runner death — process.exit abuse, OOM
|
|
730
745
|
// SIGKILL, or a crash before the in-process push. Idempotent against a
|
|
731
|
-
// successful in-runner push
|
|
746
|
+
// successful in-runner push when its local acknowledgement was lost.
|
|
732
747
|
// Its own retry diagnostics are kept in a separate log: appending them to
|
|
733
748
|
// `outputPath` after a near-gateway-sized result could hide that result from
|
|
734
749
|
// a later bounded-tail recovery read.
|
|
735
|
-
const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runnerPidPath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(terminationDiagnosticPath)} ${shellQuote(memoryLedgerPath)} ${shellQuote(`${memoryLedgerPath}.tmp`)} ${shellQuote(memoryPressurePath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)} ${shellQuote(startupDiagnosticPath)}; ( awk '$1 == "oom_kill" { print $2 }' /sys/fs/cgroup/memory.events 2>/dev/null || true ) > ${shellQuote(oomKillBaselinePath)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; ${runtimeReliabilityEnv}node ${shellQuote(crashPusherPath)} ${shellQuote(configPath)} "$code" ${shellQuote(outputPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(oomKillBaselinePath)} /sys/fs/cgroup/memory.events ${shellQuote(terminationDiagnosticPath)} > ${shellQuote(crashPusherLogPath)} 2>&1 || true; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
|
|
750
|
+
const command = `rm -f ${shellQuote(outputPath)} ${shellQuote(crashPusherLogPath)} ${shellQuote(exitCodePath)} ${shellQuote(oomKillBaselinePath)} ${shellQuote(runnerPidPath)} ${shellQuote(runtimeStartedPath)} ${shellQuote(runtimeCompletedPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(terminationDiagnosticPath)} ${shellQuote(memoryLedgerPath)} ${shellQuote(`${memoryLedgerPath}.tmp`)} ${shellQuote(memoryPressurePath)} ${shellQuote(progressEventPath)} ${shellQuote(`${progressEventPath}.*`)} ${shellQuote(startupDiagnosticPath)}; ( awk '$1 == "oom_kill" { print $2 }' /sys/fs/cgroup/memory.events 2>/dev/null || true ) > ${shellQuote(oomKillBaselinePath)}; ( ${runnerCommand} ) > ${shellQuote(outputPath)} 2>&1; code=$?; printf '%s' "$code" > ${shellQuote(exitCodePath)}; ${runtimeReliabilityEnv}node ${shellQuote(crashPusherPath)} ${shellQuote(configPath)} "$code" ${shellQuote(outputPath)} ${shellQuote(runtimeLimitMarkerPath)} ${shellQuote(oomKillBaselinePath)} /sys/fs/cgroup/memory.events ${shellQuote(terminationDiagnosticPath)} ${shellQuote(runtimeCompletedPath)} > ${shellQuote(crashPusherLogPath)} 2>&1 || true; printf 'deepline runner output captured: %s\\n' ${shellQuote(outputPath)}; exit "$code"`;
|
|
736
751
|
|
|
737
752
|
return {
|
|
738
753
|
workDir: input.workDir,
|
|
@@ -233,6 +233,7 @@ export type DetachedDaytonaRunnerSupervisor = {
|
|
|
233
233
|
export const DAYTONA_RUNNER_READY_TIMEOUT_MS =
|
|
234
234
|
RUNTIME_RELIABILITY_POLICY.sandbox.runnerReadyTimeoutMs;
|
|
235
235
|
const DAYTONA_RUNNER_READY_POLL_MS = 50;
|
|
236
|
+
const DAYTONA_RUNNER_READY_FAST_WINDOW_MS = 250;
|
|
236
237
|
|
|
237
238
|
export type DetachedRunnerReadinessPort = (
|
|
238
239
|
baselineHeartbeatAt?: string | null,
|
|
@@ -474,6 +475,7 @@ export async function confirmDetachedDaytonaRunnerReady(input: {
|
|
|
474
475
|
);
|
|
475
476
|
const pollMs = Math.max(1, input.pollMs ?? DAYTONA_RUNNER_READY_POLL_MS);
|
|
476
477
|
const deadline = now() + timeoutMs;
|
|
478
|
+
const fastStartupDeadline = now() + DAYTONA_RUNNER_READY_FAST_WINDOW_MS;
|
|
477
479
|
let schedulerDiagnosis = 'no_readiness_response';
|
|
478
480
|
let schedulerReadinessResponses = 0;
|
|
479
481
|
let retryDelayMs = pollMs;
|
|
@@ -491,8 +493,15 @@ export async function confirmDetachedDaytonaRunnerReady(input: {
|
|
|
491
493
|
schedulerDiagnosis = 'runner_heartbeat_not_observed';
|
|
492
494
|
}
|
|
493
495
|
if (read.timedOut) break;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
+
// A healthy store is waiting for a fresh heartbeat, not recovering from
|
|
497
|
+
// an outage. Avoid compounding its startup delay with the runner's own
|
|
498
|
+
// park-acknowledgement backoff. Only the first 250ms keeps the 50ms cadence;
|
|
499
|
+
// unavailable reads and longer initialization retain exponential backoff.
|
|
500
|
+
const fastStartupRead =
|
|
501
|
+
read.response !== null && now() < fastStartupDeadline;
|
|
502
|
+
const delayMs = fastStartupRead ? pollMs : retryDelayMs;
|
|
503
|
+
await sleep(Math.min(delayMs, Math.max(1, deadline - now())));
|
|
504
|
+
retryDelayMs = fastStartupRead ? pollMs : Math.min(1_000, retryDelayMs * 2);
|
|
496
505
|
}
|
|
497
506
|
|
|
498
507
|
const inspect = (sandbox: DaytonaSandbox) =>
|
|
@@ -308,8 +308,12 @@ class DaytonaUploadDeadlineBreachError extends Error {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
export const daytonaSdkClientFactory = {
|
|
311
|
-
create(
|
|
312
|
-
|
|
311
|
+
create(
|
|
312
|
+
input: DaytonaClientOptions,
|
|
313
|
+
signal?: AbortSignal,
|
|
314
|
+
onCreateStage?: Parameters<typeof createDaytonaLaunchClient>[2],
|
|
315
|
+
): DaytonaClient {
|
|
316
|
+
return createDaytonaLaunchClient(input, signal, onCreateStage);
|
|
313
317
|
},
|
|
314
318
|
/** Request-scoped native deadlines for detached recovery and cleanup. */
|
|
315
319
|
createControl: createDaytonaControlClient,
|
|
@@ -1153,7 +1157,16 @@ function emitDaytonaStage(
|
|
|
1153
1157
|
stage,
|
|
1154
1158
|
...extra,
|
|
1155
1159
|
};
|
|
1156
|
-
|
|
1160
|
+
try {
|
|
1161
|
+
console.info('[play-runner.daytona.stage]', JSON.stringify(payload));
|
|
1162
|
+
} catch {
|
|
1163
|
+
// Diagnostic delivery never changes resource ownership or command acknowledgement.
|
|
1164
|
+
try {
|
|
1165
|
+
console.error('[play-runner.daytona.stage.failed]', stage);
|
|
1166
|
+
} catch {
|
|
1167
|
+
// No log sink is available; execution still owns its normal lifecycle fences.
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1157
1170
|
}
|
|
1158
1171
|
|
|
1159
1172
|
async function downloadDaytonaTextFile(
|
|
@@ -1326,6 +1339,8 @@ function prepareDaytonaExecution(
|
|
|
1326
1339
|
const daytona = daytonaSdkClientFactory.create(
|
|
1327
1340
|
daytonaOptions,
|
|
1328
1341
|
callbacks?.cancellationSignal,
|
|
1342
|
+
(stage, timing) =>
|
|
1343
|
+
emitDaytonaStage(callbacks, input.context, stage, timing),
|
|
1329
1344
|
);
|
|
1330
1345
|
const bundlePromise = buildPlayRunnerBundle();
|
|
1331
1346
|
const sandboxLifecycle = createOneShotDaytonaSandboxLifecycle({
|
|
@@ -1453,6 +1468,8 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1453
1468
|
let cancellationRequested = false;
|
|
1454
1469
|
let cancellationCleanupStarted = false;
|
|
1455
1470
|
let activeAcquiredResource: AcquiredDaytonaSandbox | null = null;
|
|
1471
|
+
let resourceAccountingPending = false;
|
|
1472
|
+
let resourceAccountingFailed = false;
|
|
1456
1473
|
const uploadDeadlineBreaches: DaytonaUploadAttemptTiming[] = [];
|
|
1457
1474
|
const reportedSandboxIds = new Set<string>();
|
|
1458
1475
|
const reportedSandboxEndTimes = new Map<string, number | null>();
|
|
@@ -1521,6 +1538,12 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1521
1538
|
if (activeAcquiredResource && !activeAcquiredResource.billingEndedAt) {
|
|
1522
1539
|
activeAcquiredResource.billingEndedAt = Date.now();
|
|
1523
1540
|
}
|
|
1541
|
+
// Publication may commit after a lost response or lose its attempt fence.
|
|
1542
|
+
// Join it before deciding whether this backend still owns deletion.
|
|
1543
|
+
if (resourceAccountingPending || resourceAccountingFailed) {
|
|
1544
|
+
cancelExecution(new Error(DAYTONA_CANCELLED_ERROR));
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1524
1547
|
if (cancellationCleanupStarted) {
|
|
1525
1548
|
cancelExecution(new Error(DAYTONA_CANCELLED_ERROR));
|
|
1526
1549
|
return;
|
|
@@ -1550,6 +1573,7 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1550
1573
|
executionAttempt += 1
|
|
1551
1574
|
) {
|
|
1552
1575
|
let sandboxForAttempt: DaytonaSandbox | null = null;
|
|
1576
|
+
let resourceAccounting: Promise<void> | null = null;
|
|
1553
1577
|
const attemptStartedAt = Date.now();
|
|
1554
1578
|
try {
|
|
1555
1579
|
const acquiredSandbox = await Promise.race([
|
|
@@ -1562,15 +1586,27 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1562
1586
|
acquiredSandbox.billingStartedAt - startedAt;
|
|
1563
1587
|
const sandbox = acquiredSandbox.sandbox;
|
|
1564
1588
|
sandboxForAttempt = sandbox;
|
|
1565
|
-
|
|
1566
|
-
//
|
|
1567
|
-
//
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1589
|
+
// Payload upload and session allocation do not execute customer code.
|
|
1590
|
+
// Overlap them with accounting, but join every resource ACK before
|
|
1591
|
+
// command dispatch, retry, or cancellation cleanup.
|
|
1592
|
+
resourceAccountingPending = true;
|
|
1593
|
+
resourceAccounting = (async () => {
|
|
1594
|
+
await reportRuntimeResource(acquiredSandbox);
|
|
1595
|
+
await sandboxLifecycle.settlePendingCreates();
|
|
1596
|
+
for (const acquired of sandboxLifecycle.acquiredSandboxes()) {
|
|
1597
|
+
await reportRuntimeResource(acquired);
|
|
1598
|
+
}
|
|
1599
|
+
})();
|
|
1600
|
+
// Observe settlement immediately; the joins below propagate failures.
|
|
1601
|
+
void resourceAccounting.then(
|
|
1602
|
+
() => {
|
|
1603
|
+
resourceAccountingPending = false;
|
|
1604
|
+
},
|
|
1605
|
+
() => {
|
|
1606
|
+
resourceAccountingPending = false;
|
|
1607
|
+
resourceAccountingFailed = true;
|
|
1608
|
+
},
|
|
1609
|
+
);
|
|
1574
1610
|
throwIfCancellationRequested();
|
|
1575
1611
|
|
|
1576
1612
|
const { workdir: workDir } = loadDaytonaRunnerPathsConfig();
|
|
@@ -1586,6 +1622,7 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1586
1622
|
0,
|
|
1587
1623
|
Math.floor(config.context.runAttempt ?? 0),
|
|
1588
1624
|
);
|
|
1625
|
+
let commandAcceptedAtMs: number | null = null;
|
|
1589
1626
|
const detachedRunner = prepareDetachedDaytonaRunner({
|
|
1590
1627
|
sandbox,
|
|
1591
1628
|
sessionId,
|
|
@@ -1603,12 +1640,29 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1603
1640
|
},
|
|
1604
1641
|
cancellation: cancellationPromise,
|
|
1605
1642
|
onCommandAccepted: async () => {
|
|
1643
|
+
commandAcceptedAtMs = Date.now();
|
|
1644
|
+
emitDaytonaStage(callbacks, config.context, 'execute:accepted', {
|
|
1645
|
+
elapsedMs: commandAcceptedAtMs - startedAt,
|
|
1646
|
+
});
|
|
1606
1647
|
await callbacks?.onRunnerCommandAccepted?.({
|
|
1607
1648
|
provider: 'daytona',
|
|
1608
1649
|
sandboxId: sandbox.id,
|
|
1609
1650
|
});
|
|
1610
1651
|
},
|
|
1611
1652
|
onReady: async (ready) => {
|
|
1653
|
+
const heartbeatReadyAtMs = Date.now();
|
|
1654
|
+
emitDaytonaStage(
|
|
1655
|
+
callbacks,
|
|
1656
|
+
config.context,
|
|
1657
|
+
'execute:heartbeat_ready',
|
|
1658
|
+
{
|
|
1659
|
+
elapsedMs: heartbeatReadyAtMs - startedAt,
|
|
1660
|
+
commandAcceptedToHeartbeatMs:
|
|
1661
|
+
commandAcceptedAtMs === null
|
|
1662
|
+
? null
|
|
1663
|
+
: heartbeatReadyAtMs - commandAcceptedAtMs,
|
|
1664
|
+
},
|
|
1665
|
+
);
|
|
1612
1666
|
await callbacks?.onDetachedRunnerReady?.({
|
|
1613
1667
|
provider: 'daytona',
|
|
1614
1668
|
sandboxId: sandbox.id,
|
|
@@ -1649,8 +1703,13 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1649
1703
|
sandbox,
|
|
1650
1704
|
DAYTONA_UPLOAD_ATTEMPT_DEADLINE_MS,
|
|
1651
1705
|
);
|
|
1706
|
+
const finishUpload = () => {
|
|
1707
|
+
uploadScope.dispose();
|
|
1708
|
+
if (uploadDeadlineTimer) clearTimeout(uploadDeadlineTimer);
|
|
1709
|
+
uploadDeadlineTimer = null;
|
|
1710
|
+
};
|
|
1652
1711
|
try {
|
|
1653
|
-
|
|
1712
|
+
const upload = Promise.race([
|
|
1654
1713
|
stageDaytonaRunnerPayload({
|
|
1655
1714
|
sandbox: uploadScope.sandbox,
|
|
1656
1715
|
bundlePromise,
|
|
@@ -1662,8 +1721,17 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1662
1721
|
}),
|
|
1663
1722
|
uploadDeadlinePromise,
|
|
1664
1723
|
cancellationPromise,
|
|
1665
|
-
])
|
|
1724
|
+
])
|
|
1725
|
+
.then((payload) => {
|
|
1726
|
+
runtimeTiming.daytonaUploadMs = Date.now() - uploadStartedAt;
|
|
1727
|
+
return payload;
|
|
1728
|
+
})
|
|
1729
|
+
.finally(finishUpload);
|
|
1730
|
+
[stagedPayload] = await Promise.all([upload, resourceAccounting]);
|
|
1666
1731
|
} catch (error) {
|
|
1732
|
+
// A failed or lost publication response keeps cleanup with the
|
|
1733
|
+
// scheduler, even when upload or cancellation failed first.
|
|
1734
|
+
await resourceAccounting;
|
|
1667
1735
|
if (error instanceof DaytonaUploadDeadlineBreachError) {
|
|
1668
1736
|
const latestTiming =
|
|
1669
1737
|
error.attemptTimings[error.attemptTimings.length - 1];
|
|
@@ -1691,12 +1759,8 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1691
1759
|
}
|
|
1692
1760
|
throw error;
|
|
1693
1761
|
} finally {
|
|
1694
|
-
|
|
1695
|
-
if (uploadDeadlineTimer) {
|
|
1696
|
-
clearTimeout(uploadDeadlineTimer);
|
|
1697
|
-
}
|
|
1762
|
+
finishUpload();
|
|
1698
1763
|
}
|
|
1699
|
-
runtimeTiming.daytonaUploadMs = Date.now() - uploadStartedAt;
|
|
1700
1764
|
throwIfCancellationRequested();
|
|
1701
1765
|
|
|
1702
1766
|
emitDaytonaStage(callbacks, config.context, 'execute:start', {
|
|
@@ -1785,6 +1849,7 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1785
1849
|
runtimeTiming,
|
|
1786
1850
|
};
|
|
1787
1851
|
} catch (error) {
|
|
1852
|
+
if (resourceAccounting) await resourceAccounting;
|
|
1788
1853
|
if (cancellationRequested || callbacks?.cancellationSignal?.aborted) {
|
|
1789
1854
|
onCancel();
|
|
1790
1855
|
throw new Error(DAYTONA_CANCELLED_ERROR);
|
|
@@ -1862,7 +1927,7 @@ export const daytonaPlayRunnerBackend: PlayRunnerBackend = {
|
|
|
1862
1927
|
);
|
|
1863
1928
|
} finally {
|
|
1864
1929
|
callbacks?.cancellationSignal?.removeEventListener('abort', onCancel);
|
|
1865
|
-
if (cancellationRequested) {
|
|
1930
|
+
if (cancellationRequested && !resourceAccountingFailed) {
|
|
1866
1931
|
await sandboxLifecycle.settlePendingCreates();
|
|
1867
1932
|
for (const acquired of sandboxLifecycle.acquiredSandboxes()) {
|
|
1868
1933
|
try {
|