deepline 0.3.128 → 0.3.129
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 +34 -9
- package/dist/bundling-sources/sdk/src/http.ts +22 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +22 -0
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +265 -2
- package/dist/bundling-sources/shared_libs/play-runtime/bounded-batch-function.ts +682 -0
- package/dist/bundling-sources/shared_libs/play-runtime/child-execution-strategy.ts +21 -5
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +5390 -1732
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +107 -1
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/commands/roll-execution-relay.ts +7 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +229 -7
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +25 -4
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-capacity.ts +71 -0
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-gateway-drain.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/runtime-topology.ts +4 -1
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +694 -28
- package/dist/bundling-sources/shared_libs/play-runtime/egress-bandwidth-probe.ts +167 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execute-server-timing.ts +103 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-receipt-output-reference.ts +34 -0
- package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-response-size.ts +27 -0
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +66 -1
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +425 -71
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +210 -32
- package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +27 -13
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +19 -6
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +61 -2
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +33 -1
- package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +42 -1
- package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +11 -11
- package/dist/bundling-sources/shared_libs/play-runtime/ledger-safe-payload.ts +49 -16
- package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +1653 -98
- package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +807 -0
- package/dist/bundling-sources/shared_libs/play-runtime/memory-pressure-signal.ts +138 -0
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +85 -3
- package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +60 -2
- package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +46 -1
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +70 -27
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +56 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/adaptive-provider-capacity-controller.ts +192 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/epoch-aimd-rate-controller.ts +194 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/fixture-capacity-simulator.ts +220 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/gradient2-concurrency-controller.ts +214 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-capacity-policy.ts +43 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-concurrency-policy.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-rate-policy.ts +95 -0
- package/dist/bundling-sources/shared_libs/play-runtime/provider-capacity/provider-throttle-classifier.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +1535 -11
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +49 -2
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +55 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/egress-probe.ts +221 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +339 -29
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-deadline.ts +28 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +192 -165
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +6 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +90 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +281 -6
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +27 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +19 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +108 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +40 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +11 -5
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +30 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api-compression.ts +276 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +723 -115
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +98 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +3 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +41 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +448 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-map-row-feed.ts +215 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +11 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +161 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-value.ts +184 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +607 -121
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-placement-policy.ts +4 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-writer.ts +21 -0
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +15 -2
- package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +71 -14
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +288 -119
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +8 -6
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +28 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/canonical-integration-operation-store.ts +179 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +80 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +31 -2
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-store-contract.ts +104 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-reference.ts +47 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-retirement.ts +193 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/integration-operation-value-storage.ts +420 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +41 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +134 -3
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +1657 -95
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +885 -73
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-completion-coalescer.ts +452 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +601 -42
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +371 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +86 -7
- package/dist/bundling-sources/shared_libs/play-runtime/secret-redaction.ts +153 -22
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +188 -38
- package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +28 -13
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +44 -1
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +56 -4
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +2 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +16 -10
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +4 -1
- package/dist/cli/index.js +250 -38
- package/dist/cli/index.mjs +250 -38
- package/dist/{compiler-manifest-DfSnbCTW.d.mts → compiler-manifest-BIqRyj5m.d.mts} +1 -1
- package/dist/{compiler-manifest-DfSnbCTW.d.ts → compiler-manifest-BIqRyj5m.d.ts} +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +231 -35
- package/dist/index.mjs +231 -35
- package/dist/install-integrity.json +31 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +65 -1
- 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
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts
CHANGED
|
@@ -40,7 +40,6 @@ import {
|
|
|
40
40
|
fallbackRuntimeTrafficPolicyForUnavailableControlPlane,
|
|
41
41
|
getRuntimeTrafficPolicyViaAppRuntime,
|
|
42
42
|
isLegacyRuntimeTrafficPolicyControlPlaneResponse,
|
|
43
|
-
recordFirstClaimLatencyViaAppRuntime,
|
|
44
43
|
upsertComputeBillingSessionViaAppRuntime,
|
|
45
44
|
type WorkerRuntimeApiContext,
|
|
46
45
|
} from '../app-runtime-api';
|
|
@@ -49,6 +48,7 @@ import { RUNTIME_RELIABILITY_POLICY } from '../runtime-reliability-policy';
|
|
|
49
48
|
import type { RuntimeTrafficPolicy } from '../runtime-traffic-policy';
|
|
50
49
|
import { runtimeLimitExceededCause } from '../run-failure';
|
|
51
50
|
import {
|
|
51
|
+
recoveryForDaytonaSandboxAcquisitionUnavailable,
|
|
52
52
|
recoveryForRuntimeInitializationTransportFailure,
|
|
53
53
|
recoveryForRuntimeTrafficPolicy,
|
|
54
54
|
} from '../play-run-recovery-policy';
|
|
@@ -60,7 +60,10 @@ import type {
|
|
|
60
60
|
PlayRunnerExecutionConfig,
|
|
61
61
|
PlayRunnerResult,
|
|
62
62
|
} from '../protocol';
|
|
63
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
RuntimeResourceFenceLostError,
|
|
65
|
+
type PlayRunnerRuntimeResource,
|
|
66
|
+
} from '../runner-backends/types';
|
|
64
67
|
import type { PlayBundleArtifact } from '../../plays/artifact-types';
|
|
65
68
|
import {
|
|
66
69
|
readRuntimeSheetRowOutcomeCounts,
|
|
@@ -73,6 +76,7 @@ import { installPgRuntimePoolDriver } from '../runtime-pg-driver-pg';
|
|
|
73
76
|
import {
|
|
74
77
|
isManagedSandboxRuntimeBackend,
|
|
75
78
|
normalizePlayRuntimeBackend,
|
|
79
|
+
PLAY_RUNTIME_BACKENDS,
|
|
76
80
|
type PlayRuntimeBackendId,
|
|
77
81
|
} from '../backend';
|
|
78
82
|
import {
|
|
@@ -84,7 +88,6 @@ import { retryableRuntimeInitializationFailureReason } from '../runner-backends/
|
|
|
84
88
|
import {
|
|
85
89
|
isRuntimeSandboxCanaryProduction,
|
|
86
90
|
resolveLaunchRuntimeSandboxPlacementPolicy,
|
|
87
|
-
runtimeSandboxPlacementPoliciesForBackend,
|
|
88
91
|
selectRuntimeSandboxCanary,
|
|
89
92
|
} from '../runtime-sandbox-placement-policy';
|
|
90
93
|
import { shouldUseRuntimeSchedulerDirectNotify } from '../runtime-scheduler-topology';
|
|
@@ -149,6 +152,7 @@ import {
|
|
|
149
152
|
recordPostgresSchedulerLateManagedSandboxOperationForCleanup,
|
|
150
153
|
recordPostgresSchedulerLateRuntimeResourceForCleanup,
|
|
151
154
|
recordPostgresSchedulerManagedSandboxOperationLive,
|
|
155
|
+
readPostgresSchedulerManagedSandboxOperationAlreadyLive,
|
|
152
156
|
recordPostgresSchedulerReconciledModalResourcesForCleanup,
|
|
153
157
|
recordPostgresSchedulerRuntimeLifecycleEvent,
|
|
154
158
|
recordPostgresSchedulerSandboxCrashDiagnostic,
|
|
@@ -194,9 +198,15 @@ import {
|
|
|
194
198
|
type PlayRunAttemptWorkerTerminalProjectionPort,
|
|
195
199
|
} from '../play-runs/attempts';
|
|
196
200
|
import { transitionPreCodePlayRunRecovery } from './play-run-recovery';
|
|
197
|
-
import {
|
|
201
|
+
import {
|
|
202
|
+
acquirePostgresRateState,
|
|
203
|
+
penalizePostgresRateState,
|
|
204
|
+
} from './postgres-rate-state';
|
|
198
205
|
import { verifyRuntimeReceiptGatewayHealth } from './runtime-receipt-gateway-health';
|
|
199
|
-
import {
|
|
206
|
+
import {
|
|
207
|
+
runtimeSandboxPlacementPoliciesForWorkerEnv,
|
|
208
|
+
runtimeSandboxProviderCapabilities,
|
|
209
|
+
} from './absurd-worker-required-env';
|
|
200
210
|
import {
|
|
201
211
|
acquirePgNotifyHub,
|
|
202
212
|
isRuntimeSchedulerCapacityError,
|
|
@@ -261,6 +271,7 @@ import {
|
|
|
261
271
|
runtimeSandboxCapacityAdmissionMode,
|
|
262
272
|
RuntimeSandboxCapacityLimitError,
|
|
263
273
|
} from './runtime-sandbox-capacity';
|
|
274
|
+
import { runtimeSandboxProviderForResourceKind } from './runtime-sandbox-operation';
|
|
264
275
|
import {
|
|
265
276
|
createPostgresSandboxCleanupStore,
|
|
266
277
|
createSandboxCleanupJob,
|
|
@@ -718,6 +729,16 @@ export type AbsurdRuntimeWorkerDeps = {
|
|
|
718
729
|
readDetachedRunnerRuntimeCompletion?: (
|
|
719
730
|
suspension: DetachedRunnerSuspension,
|
|
720
731
|
) => Promise<number | null>;
|
|
732
|
+
/**
|
|
733
|
+
* A bounded provider inspection of the captured terminal written by a
|
|
734
|
+
* detached runner that lost its gateway. This never executes customer code:
|
|
735
|
+
* it can only recover the result the sandbox already emitted before exit.
|
|
736
|
+
*/
|
|
737
|
+
inspectDetachedRunner?: (suspension: DetachedRunnerSuspension) => Promise<{
|
|
738
|
+
exitCode: number | null;
|
|
739
|
+
result: PlayRunnerResult | null;
|
|
740
|
+
diagnosis: { stage: string; detail: string | null };
|
|
741
|
+
} | null>;
|
|
721
742
|
readSandboxCrashDiagnostic?: (
|
|
722
743
|
request: PostgresSchedulerSandboxCrashDiagnosticRequest,
|
|
723
744
|
routingDomain: string | null,
|
|
@@ -789,6 +810,11 @@ function buildDefaultDeps(absurd: Absurd): AbsurdRuntimeWorkerDeps {
|
|
|
789
810
|
suspension.runtimeCompletedPath,
|
|
790
811
|
)
|
|
791
812
|
: Promise.resolve(null),
|
|
813
|
+
inspectDetachedRunner: (suspension) =>
|
|
814
|
+
defaultRuntimeSandboxReconciliation.inspectDetachedRunner(
|
|
815
|
+
runtimeSandboxRefFromSuspension(suspension),
|
|
816
|
+
suspension,
|
|
817
|
+
),
|
|
792
818
|
readSandboxCrashDiagnostic: (request, routingDomain) =>
|
|
793
819
|
readDetachedDaytonaCrashDiagnostic({
|
|
794
820
|
sandboxId: request.sandboxId,
|
|
@@ -1783,6 +1809,28 @@ function sandboxCapacityExceededCause(): string {
|
|
|
1783
1809
|
return `${SANDBOX_CAPACITY_EXCEEDED_CODE}: This organization's execution concurrency limit is currently full.`;
|
|
1784
1810
|
}
|
|
1785
1811
|
|
|
1812
|
+
/**
|
|
1813
|
+
* The existing capacity lease and operation tables own Daytona and Modal only.
|
|
1814
|
+
* Keep this narrowing at their adapter seam: the shared Sandbox Runs contract
|
|
1815
|
+
* remains provider-neutral, while a future provider must add its durable
|
|
1816
|
+
* capacity/cleanup owner before it can receive one of these leases.
|
|
1817
|
+
*/
|
|
1818
|
+
type ManagedSandboxCapacityResource = PlayRunnerRuntimeResource & {
|
|
1819
|
+
kind: 'daytona_sandbox' | 'modal_sandbox';
|
|
1820
|
+
sandboxCapacityLeaseId: string;
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
function isManagedSandboxCapacityResource(
|
|
1824
|
+
resource: PlayRunnerRuntimeResource,
|
|
1825
|
+
): resource is ManagedSandboxCapacityResource {
|
|
1826
|
+
return (
|
|
1827
|
+
(resource.kind === 'daytona_sandbox' ||
|
|
1828
|
+
resource.kind === 'modal_sandbox') &&
|
|
1829
|
+
typeof resource.sandboxCapacityLeaseId === 'string' &&
|
|
1830
|
+
resource.sandboxCapacityLeaseId.trim().length > 0
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1786
1834
|
async function terminalizeSandboxCapacityRejection(input: {
|
|
1787
1835
|
deps: AbsurdRuntimeWorkerDeps;
|
|
1788
1836
|
options: Pick<PostgresSchedulerOptions, 'schema'>;
|
|
@@ -1969,7 +2017,7 @@ async function prepareAbsurdAttempt(input: {
|
|
|
1969
2017
|
launch.runtimeBackend || configuredBackend,
|
|
1970
2018
|
);
|
|
1971
2019
|
const configuredPlacementPolicies =
|
|
1972
|
-
|
|
2020
|
+
runtimeSandboxPlacementPoliciesForWorkerEnv(configuredBackend);
|
|
1973
2021
|
const launchPlacementPolicy = resolveLaunchRuntimeSandboxPlacementPolicy({
|
|
1974
2022
|
runtimeBackend: launchBackend,
|
|
1975
2023
|
runtimeSandboxPlacementPolicyId: launch.runtimeSandboxPlacementPolicyId,
|
|
@@ -2210,27 +2258,13 @@ async function executeAbsurdAttemptAdapter(
|
|
|
2210
2258
|
});
|
|
2211
2259
|
}
|
|
2212
2260
|
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
firstClaimLatencyMs,
|
|
2221
|
-
},
|
|
2222
|
-
),
|
|
2223
|
-
)
|
|
2224
|
-
.catch((error) => {
|
|
2225
|
-
console.warn(
|
|
2226
|
-
'[absurd-runtime.worker.first-claim-latency-write-failed]',
|
|
2227
|
-
{
|
|
2228
|
-
runId,
|
|
2229
|
-
error: error instanceof Error ? error.message : String(error),
|
|
2230
|
-
},
|
|
2231
|
-
);
|
|
2232
|
-
});
|
|
2233
|
-
}
|
|
2261
|
+
// The Postgres `run.started` outbox projection already carries this
|
|
2262
|
+
// scheduler-owned measurement into the initial Convex admission. Do not
|
|
2263
|
+
// issue a second fire-and-forget write against the hot `playRuns` document:
|
|
2264
|
+
// it races the worker's first ledger append and turns an observability
|
|
2265
|
+
// metric into an OCC retry on the runtime critical path. Keep the public
|
|
2266
|
+
// app-runtime action registered for mixed-version workers, but let the
|
|
2267
|
+
// durable start projection be the single writer here.
|
|
2234
2268
|
|
|
2235
2269
|
let executionLaunch = launch;
|
|
2236
2270
|
try {
|
|
@@ -2991,6 +3025,7 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
2991
3025
|
options,
|
|
2992
3026
|
),
|
|
2993
3027
|
),
|
|
3028
|
+
inspectDetachedRunner: deps.inspectDetachedRunner,
|
|
2994
3029
|
deleteRuntimeSandbox: deps.deleteRuntimeSandbox,
|
|
2995
3030
|
deleteRuntimeSandboxRef: deps.deleteRuntimeSandboxRef,
|
|
2996
3031
|
sandboxGcTimeoutMs: deps.sandboxGcTimeoutMs,
|
|
@@ -3054,6 +3089,10 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3054
3089
|
let terminalResultFromDetachedRunner = false;
|
|
3055
3090
|
let terminalLogProducerAttempt: number | undefined;
|
|
3056
3091
|
let terminalDetachedSuspension: DetachedRunnerSuspension | undefined;
|
|
3092
|
+
let daytonaStartRateConfig: {
|
|
3093
|
+
ratePerMinute: number;
|
|
3094
|
+
maximumRatePerMinute: number;
|
|
3095
|
+
} | null = null;
|
|
3057
3096
|
try {
|
|
3058
3097
|
if (pendingDetachedRunner) {
|
|
3059
3098
|
// Push execution (B2-final): this leg woke a `detached_runner` park.
|
|
@@ -3078,6 +3117,7 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3078
3117
|
options,
|
|
3079
3118
|
),
|
|
3080
3119
|
),
|
|
3120
|
+
inspectDetachedRunner: deps.inspectDetachedRunner,
|
|
3081
3121
|
readDetachedRunnerRuntimeCompletion:
|
|
3082
3122
|
deps.readDetachedRunnerRuntimeCompletion,
|
|
3083
3123
|
deleteRuntimeSandbox: deps.deleteRuntimeSandbox,
|
|
@@ -3193,8 +3233,29 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3193
3233
|
});
|
|
3194
3234
|
trafficPolicy = fallback;
|
|
3195
3235
|
}
|
|
3236
|
+
const defaultDaytonaStartRatePerMinute =
|
|
3237
|
+
launch.runtimeBackend === PLAY_RUNTIME_BACKENDS.daytona
|
|
3238
|
+
? RUNTIME_CAPACITY_POLICY.sandboxAcquisition
|
|
3239
|
+
.daytonaInitialStartsPerMinute
|
|
3240
|
+
: null;
|
|
3241
|
+
const effectiveDaytonaStartRatePerMinute =
|
|
3242
|
+
trafficPolicy.sandboxStartsPerMinute ??
|
|
3243
|
+
defaultDaytonaStartRatePerMinute;
|
|
3244
|
+
daytonaStartRateConfig =
|
|
3245
|
+
effectiveDaytonaStartRatePerMinute === null
|
|
3246
|
+
? null
|
|
3247
|
+
: {
|
|
3248
|
+
ratePerMinute: effectiveDaytonaStartRatePerMinute,
|
|
3249
|
+
maximumRatePerMinute:
|
|
3250
|
+
trafficPolicy.sandboxStartsPerMinute === null
|
|
3251
|
+
? RUNTIME_CAPACITY_POLICY.sandboxAcquisition
|
|
3252
|
+
.daytonaMaximumStartsPerMinute
|
|
3253
|
+
: effectiveDaytonaStartRatePerMinute,
|
|
3254
|
+
};
|
|
3196
3255
|
await enforceRuntimeTrafficPolicyBeforeSandboxStart({
|
|
3197
3256
|
policy: trafficPolicy,
|
|
3257
|
+
defaultSandboxStartsPerMinute:
|
|
3258
|
+
defaultDaytonaStartRatePerMinute,
|
|
3198
3259
|
nowMs: Date.now(),
|
|
3199
3260
|
acquireStartPermit: async (sandboxStartsPerMinute) =>
|
|
3200
3261
|
await deps.runWithClient((client) =>
|
|
@@ -3210,8 +3271,16 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3210
3271
|
// start-rate ceiling rather than a minute-sized burst.
|
|
3211
3272
|
windowMs: Math.ceil(60_000 / sandboxStartsPerMinute),
|
|
3212
3273
|
maxConcurrency: null,
|
|
3274
|
+
adaptiveMaxRps:
|
|
3275
|
+
(daytonaStartRateConfig?.maximumRatePerMinute ??
|
|
3276
|
+
sandboxStartsPerMinute) /
|
|
3277
|
+
60,
|
|
3213
3278
|
},
|
|
3214
3279
|
],
|
|
3280
|
+
// The permit itself is the successful admission
|
|
3281
|
+
// observation that lets the fleet-wide AIMD controller
|
|
3282
|
+
// ramp. Provider pressure is fed back in the catch path.
|
|
3283
|
+
observedSuccesses: 1,
|
|
3215
3284
|
}),
|
|
3216
3285
|
),
|
|
3217
3286
|
});
|
|
@@ -3263,6 +3332,11 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3263
3332
|
return { kind: 'allowed' };
|
|
3264
3333
|
},
|
|
3265
3334
|
async reserveCapacity({ provider, providerAttempt }) {
|
|
3335
|
+
if (provider === 'agentcore_runtime') {
|
|
3336
|
+
throw new Error(
|
|
3337
|
+
'AgentCore cannot use the Daytona/Modal capacity ledger before its provider-specific durable capacity owner is installed.',
|
|
3338
|
+
);
|
|
3339
|
+
}
|
|
3266
3340
|
const mode = runtimeSandboxCapacityAdmissionMode();
|
|
3267
3341
|
const reserved = await deps.runWithClient((client) =>
|
|
3268
3342
|
reserveRuntimeSandboxOperation(
|
|
@@ -3345,22 +3419,38 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3345
3419
|
resource,
|
|
3346
3420
|
);
|
|
3347
3421
|
const recorded = await deps.runWithClient(async (client) => {
|
|
3348
|
-
if (
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3422
|
+
if (isManagedSandboxCapacityResource(runnerResource)) {
|
|
3423
|
+
const promoted =
|
|
3424
|
+
await recordPostgresSchedulerManagedSandboxOperationLive(
|
|
3425
|
+
client,
|
|
3426
|
+
{
|
|
3427
|
+
runId,
|
|
3428
|
+
attempt: generation,
|
|
3429
|
+
leaseToken,
|
|
3430
|
+
resource: runnerResource,
|
|
3431
|
+
},
|
|
3432
|
+
options,
|
|
3433
|
+
);
|
|
3434
|
+
if (promoted) return true;
|
|
3435
|
+
// The promotion is a one-shot reserved->live compare-and-set,
|
|
3436
|
+
// so it also rejects this attempt re-reporting a sandbox it
|
|
3437
|
+
// already promoted -- which a provider retry inside one
|
|
3438
|
+
// attempt does whenever it retires an earlier sandbox. Prove
|
|
3439
|
+
// from durable state which case this is instead of assuming
|
|
3440
|
+
// either: only an intact fence over an already-live operation
|
|
3441
|
+
// for this exact sandbox is idempotent success. Everything
|
|
3442
|
+
// else stays a loud fence loss.
|
|
3443
|
+
return await readPostgresSchedulerManagedSandboxOperationAlreadyLive(
|
|
3354
3444
|
client,
|
|
3355
3445
|
{
|
|
3356
3446
|
runId,
|
|
3357
3447
|
attempt: generation,
|
|
3358
3448
|
leaseToken,
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3449
|
+
operationKey: runnerResource.sandboxCapacityLeaseId,
|
|
3450
|
+
provider: runtimeSandboxProviderForResourceKind(
|
|
3451
|
+
runnerResource.kind,
|
|
3452
|
+
),
|
|
3453
|
+
sandboxId: runnerResource.sandboxId,
|
|
3364
3454
|
},
|
|
3365
3455
|
options,
|
|
3366
3456
|
);
|
|
@@ -3384,22 +3474,8 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3384
3474
|
) || runtimeSandboxCapacityAdmissionMode() === 'observe'
|
|
3385
3475
|
);
|
|
3386
3476
|
}
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
{
|
|
3390
|
-
leaseId: runnerResource.sandboxCapacityLeaseId,
|
|
3391
|
-
provider:
|
|
3392
|
-
runnerResource.kind === 'modal_sandbox'
|
|
3393
|
-
? 'modal'
|
|
3394
|
-
: 'daytona',
|
|
3395
|
-
sandboxId: runnerResource.sandboxId,
|
|
3396
|
-
routingDomain:
|
|
3397
|
-
runnerResource.kind === 'modal_sandbox'
|
|
3398
|
-
? runnerResource.modalAppId?.trim() || null
|
|
3399
|
-
: runnerResource.daytonaOrganizationId?.trim() ||
|
|
3400
|
-
null,
|
|
3401
|
-
},
|
|
3402
|
-
options,
|
|
3477
|
+
throw new Error(
|
|
3478
|
+
`Runtime resource ${runnerResource.kind} carried a capacity lease without a matching managed provider owner.`,
|
|
3403
3479
|
);
|
|
3404
3480
|
});
|
|
3405
3481
|
return recorded
|
|
@@ -3417,18 +3493,14 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3417
3493
|
);
|
|
3418
3494
|
}
|
|
3419
3495
|
const recorded = await deps.runWithClient(async (client) => {
|
|
3420
|
-
if (runnerResource
|
|
3496
|
+
if (isManagedSandboxCapacityResource(runnerResource)) {
|
|
3421
3497
|
return await recordPostgresSchedulerLateManagedSandboxOperationForCleanup(
|
|
3422
3498
|
client,
|
|
3423
3499
|
{
|
|
3424
3500
|
runId,
|
|
3425
3501
|
attempt: generation,
|
|
3426
3502
|
leaseToken,
|
|
3427
|
-
resource:
|
|
3428
|
-
...runnerResource,
|
|
3429
|
-
sandboxCapacityLeaseId:
|
|
3430
|
-
runnerResource.sandboxCapacityLeaseId,
|
|
3431
|
-
},
|
|
3503
|
+
resource: runnerResource,
|
|
3432
3504
|
},
|
|
3433
3505
|
options,
|
|
3434
3506
|
);
|
|
@@ -3446,19 +3518,8 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3446
3518
|
);
|
|
3447
3519
|
if (!resourceRecorded) return false;
|
|
3448
3520
|
if (!runnerResource.sandboxCapacityLeaseId) return true;
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
{
|
|
3452
|
-
leaseId: runnerResource.sandboxCapacityLeaseId,
|
|
3453
|
-
provider: 'modal',
|
|
3454
|
-
sandboxId: runnerResource.sandboxId,
|
|
3455
|
-
routingDomain:
|
|
3456
|
-
runnerResource.kind === 'modal_sandbox'
|
|
3457
|
-
? runnerResource.modalAppId?.trim() || null
|
|
3458
|
-
: runnerResource.daytonaOrganizationId?.trim() ||
|
|
3459
|
-
null,
|
|
3460
|
-
},
|
|
3461
|
-
options,
|
|
3521
|
+
throw new Error(
|
|
3522
|
+
'Late Modal resource carried a capacity lease without a matching managed provider owner.',
|
|
3462
3523
|
);
|
|
3463
3524
|
});
|
|
3464
3525
|
return recorded
|
|
@@ -3569,9 +3630,35 @@ async function executeAssignedAbsurdAttempt(input: {
|
|
|
3569
3630
|
}
|
|
3570
3631
|
} catch (error) {
|
|
3571
3632
|
await cleanupAfterExecutionError(error, runnerConfig);
|
|
3633
|
+
const recoveryError =
|
|
3634
|
+
recoveryForDaytonaSandboxAcquisitionUnavailable(error) ?? error;
|
|
3635
|
+
if (
|
|
3636
|
+
recoveryError !== error &&
|
|
3637
|
+
daytonaStartRateConfig !== null
|
|
3638
|
+
) {
|
|
3639
|
+
await deps.runWithClient((client) =>
|
|
3640
|
+
penalizePostgresRateState(client, {
|
|
3641
|
+
bucketId: 'runtime:traffic:sandbox-start',
|
|
3642
|
+
schedulerSchema: options.schema ?? null,
|
|
3643
|
+
cooldownMs: 15_000,
|
|
3644
|
+
rules: [
|
|
3645
|
+
{
|
|
3646
|
+
ruleId: 'runtime:traffic:sandbox-start',
|
|
3647
|
+
requestsPerWindow: 1,
|
|
3648
|
+
windowMs: Math.ceil(
|
|
3649
|
+
60_000 / daytonaStartRateConfig!.ratePerMinute,
|
|
3650
|
+
),
|
|
3651
|
+
adaptiveMaxRps:
|
|
3652
|
+
daytonaStartRateConfig!.maximumRatePerMinute / 60,
|
|
3653
|
+
maxConcurrency: null,
|
|
3654
|
+
},
|
|
3655
|
+
],
|
|
3656
|
+
}),
|
|
3657
|
+
);
|
|
3658
|
+
}
|
|
3572
3659
|
const recovery = await deps.runWithClient((client) =>
|
|
3573
3660
|
transitionPreCodePlayRunRecovery({
|
|
3574
|
-
error,
|
|
3661
|
+
error: recoveryError,
|
|
3575
3662
|
runId,
|
|
3576
3663
|
attempt: generation,
|
|
3577
3664
|
leaseToken,
|
|
@@ -3664,8 +3751,48 @@ function createAbsurdWorkerTerminalProjectionAdapter(input: {
|
|
|
3664
3751
|
fromDetachedRunner: boolean;
|
|
3665
3752
|
terminalLogProducerAttempt?: number;
|
|
3666
3753
|
}): PlayRunAttemptWorkerTerminalProjectionPort {
|
|
3754
|
+
/**
|
|
3755
|
+
* Every terminal releases what the attempt claimed. Best-effort by design:
|
|
3756
|
+
* terminal truth is already durable, and a failed release must never turn a
|
|
3757
|
+
* committed terminal into a worker error.
|
|
3758
|
+
*/
|
|
3759
|
+
const releaseAttemptReceipts = async (reason: string): Promise<void> => {
|
|
3760
|
+
await input.deps
|
|
3761
|
+
.runWithClient((client) =>
|
|
3762
|
+
releasePostgresSchedulerReceiptsForAttempt(
|
|
3763
|
+
client,
|
|
3764
|
+
{ runId: input.runId, runAttempt: input.generation },
|
|
3765
|
+
{ ...input.options, orgId: input.launch.orgId },
|
|
3766
|
+
),
|
|
3767
|
+
)
|
|
3768
|
+
.then((released) => {
|
|
3769
|
+
if (released.released > 0) {
|
|
3770
|
+
console.info('[absurd-runtime.worker] released terminal receipts', {
|
|
3771
|
+
runId: input.runId,
|
|
3772
|
+
generation: input.generation,
|
|
3773
|
+
reason,
|
|
3774
|
+
releasedReceipts: released.released,
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
})
|
|
3778
|
+
.catch((error) => {
|
|
3779
|
+
console.warn(
|
|
3780
|
+
'[absurd-runtime.worker] terminal receipt release failed',
|
|
3781
|
+
{
|
|
3782
|
+
runId: input.runId,
|
|
3783
|
+
generation: input.generation,
|
|
3784
|
+
reason,
|
|
3785
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3786
|
+
},
|
|
3787
|
+
);
|
|
3788
|
+
});
|
|
3789
|
+
};
|
|
3667
3790
|
return createPlayRunAttemptWorkerTerminalProjection({
|
|
3668
3791
|
async observeFenceLost() {
|
|
3792
|
+
// A lost fence means this attempt is dead, which a cancelled run is the
|
|
3793
|
+
// loudest case of: its receipts must not stay leased to a generation
|
|
3794
|
+
// that will never complete them.
|
|
3795
|
+
await releaseAttemptReceipts('fence_lost');
|
|
3669
3796
|
await settleObservedTerminal({
|
|
3670
3797
|
deps: input.deps,
|
|
3671
3798
|
launch: input.launch,
|
|
@@ -3687,36 +3814,7 @@ function createAbsurdWorkerTerminalProjectionAdapter(input: {
|
|
|
3687
3814
|
});
|
|
3688
3815
|
},
|
|
3689
3816
|
async releaseFailedAttempt() {
|
|
3690
|
-
await
|
|
3691
|
-
.runWithClient((client) =>
|
|
3692
|
-
releasePostgresSchedulerReceiptsForAttempt(
|
|
3693
|
-
client,
|
|
3694
|
-
{ runId: input.runId, runAttempt: input.generation },
|
|
3695
|
-
{ ...input.options, orgId: input.launch.orgId },
|
|
3696
|
-
),
|
|
3697
|
-
)
|
|
3698
|
-
.then((released) => {
|
|
3699
|
-
if (released.released > 0) {
|
|
3700
|
-
console.info(
|
|
3701
|
-
'[absurd-runtime.worker] released failed terminal receipts',
|
|
3702
|
-
{
|
|
3703
|
-
runId: input.runId,
|
|
3704
|
-
generation: input.generation,
|
|
3705
|
-
releasedReceipts: released.released,
|
|
3706
|
-
},
|
|
3707
|
-
);
|
|
3708
|
-
}
|
|
3709
|
-
})
|
|
3710
|
-
.catch((error) => {
|
|
3711
|
-
console.warn(
|
|
3712
|
-
'[absurd-runtime.worker] failed terminal receipt release failed',
|
|
3713
|
-
{
|
|
3714
|
-
runId: input.runId,
|
|
3715
|
-
generation: input.generation,
|
|
3716
|
-
error: error instanceof Error ? error.message : String(error),
|
|
3717
|
-
},
|
|
3718
|
-
);
|
|
3719
|
-
});
|
|
3817
|
+
await releaseAttemptReceipts('failed_terminal');
|
|
3720
3818
|
|
|
3721
3819
|
// A normal runner-reported failure does not enter the thrown-error
|
|
3722
3820
|
// cleanup path above. Its terminal is already durable, so leaving these
|
|
@@ -3870,12 +3968,13 @@ function throwRetryableRuntimeInitializationFailure(
|
|
|
3870
3968
|
|
|
3871
3969
|
/**
|
|
3872
3970
|
* Consume one global start permit before a first sandbox create. The limiter's
|
|
3873
|
-
* durable bucket is
|
|
3874
|
-
*
|
|
3971
|
+
* durable bucket is used for the compiled Daytona AIMD start ceiling and for
|
|
3972
|
+
* any short-lived operator policy. A long wait becomes the same finite
|
|
3875
3973
|
* recovery ledger used for platform outages.
|
|
3876
3974
|
*/
|
|
3877
3975
|
export async function enforceRuntimeTrafficPolicyBeforeSandboxStart(input: {
|
|
3878
3976
|
policy: RuntimeTrafficPolicy;
|
|
3977
|
+
defaultSandboxStartsPerMinute?: number | null;
|
|
3879
3978
|
nowMs: number;
|
|
3880
3979
|
acquireStartPermit: (sandboxStartsPerMinute: number) => Promise<{
|
|
3881
3980
|
granted: number;
|
|
@@ -3888,20 +3987,41 @@ export async function enforceRuntimeTrafficPolicyBeforeSandboxStart(input: {
|
|
|
3888
3987
|
if (input.policy.admissionMode === 'hold_new_sandbox_starts') {
|
|
3889
3988
|
throw recoveryForRuntimeTrafficPolicy({ mode: 'hold' });
|
|
3890
3989
|
}
|
|
3891
|
-
const sandboxStartsPerMinute =
|
|
3990
|
+
const sandboxStartsPerMinute =
|
|
3991
|
+
input.policy.sandboxStartsPerMinute ??
|
|
3992
|
+
input.defaultSandboxStartsPerMinute ??
|
|
3993
|
+
null;
|
|
3892
3994
|
if (sandboxStartsPerMinute === null) return;
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3995
|
+
let locallyWaitedMs = 0;
|
|
3996
|
+
for (;;) {
|
|
3997
|
+
const permit = await input.acquireStartPermit(sandboxStartsPerMinute);
|
|
3998
|
+
const scheduledAtMs = permit.scheduledAtMs?.[0] ?? input.nowMs;
|
|
3999
|
+
const schedulerNowMs = permit.serverNowMs ?? input.nowMs;
|
|
4000
|
+
const delayMs =
|
|
4001
|
+
permit.granted > 0
|
|
4002
|
+
? Math.max(0, scheduledAtMs - schedulerNowMs)
|
|
4003
|
+
: Math.max(
|
|
4004
|
+
0,
|
|
4005
|
+
permit.waitMs,
|
|
4006
|
+
scheduledAtMs > input.nowMs
|
|
4007
|
+
? scheduledAtMs - schedulerNowMs
|
|
4008
|
+
: 0,
|
|
4009
|
+
);
|
|
4010
|
+
// A sub-second schedule retains smooth pacing without spending a worker
|
|
4011
|
+
// attempt. Longer waits become a durable, bounded defer, allowing the
|
|
4012
|
+
// scheduler to serve unrelated traffic during a deliberate shed.
|
|
4013
|
+
if (delayMs > 1_000 || locallyWaitedMs + delayMs > 1_000) {
|
|
4014
|
+
throw recoveryForRuntimeTrafficPolicy({ mode: 'throttle' });
|
|
4015
|
+
}
|
|
4016
|
+
if (permit.granted > 0) {
|
|
4017
|
+
if (delayMs > 0) {
|
|
4018
|
+
await (input.sleep ?? sleep)(delayMs);
|
|
4019
|
+
}
|
|
4020
|
+
return;
|
|
4021
|
+
}
|
|
4022
|
+
const waitMs = Math.max(1, delayMs);
|
|
4023
|
+
await (input.sleep ?? sleep)(waitMs);
|
|
4024
|
+
locallyWaitedMs += waitMs;
|
|
3905
4025
|
}
|
|
3906
4026
|
}
|
|
3907
4027
|
|
|
@@ -3946,6 +4066,7 @@ async function resolveDetachedRunnerOutcome(input: {
|
|
|
3946
4066
|
updatedAt: string | null;
|
|
3947
4067
|
status: string;
|
|
3948
4068
|
} | null>;
|
|
4069
|
+
inspectDetachedRunner?: AbsurdRuntimeWorkerDeps['inspectDetachedRunner'];
|
|
3949
4070
|
readDetachedRunnerRuntimeCompletion?: AbsurdRuntimeWorkerDeps['readDetachedRunnerRuntimeCompletion'];
|
|
3950
4071
|
deleteRuntimeSandbox: AbsurdRuntimeWorkerDeps['deleteRuntimeSandbox'];
|
|
3951
4072
|
deleteRuntimeSandboxRef?: AbsurdRuntimeWorkerDeps['deleteRuntimeSandboxRef'];
|
|
@@ -4114,6 +4235,54 @@ async function resolveDetachedRunnerOutcome(input: {
|
|
|
4114
4235
|
tableNamespace: null,
|
|
4115
4236
|
});
|
|
4116
4237
|
}
|
|
4238
|
+
// The runner writes a structured terminal to its sandbox output before its
|
|
4239
|
+
// bounded terminal push. A receipt-gateway outage can exhaust that push and
|
|
4240
|
+
// expire liveness even though the sandbox cleanly stopped itself. Recover
|
|
4241
|
+
// only that already-written result before synthesizing RUNNER_LOST: this
|
|
4242
|
+
// does not execute customer code, and an unavailable inspection preserves
|
|
4243
|
+
// the existing conservative failure below.
|
|
4244
|
+
if (input.inspectDetachedRunner) {
|
|
4245
|
+
try {
|
|
4246
|
+
const inspection = await input.inspectDetachedRunner(suspension);
|
|
4247
|
+
if (inspection?.result && inspection.result.status !== 'suspended') {
|
|
4248
|
+
console.info(
|
|
4249
|
+
'[absurd-runtime.worker] detached_runner_liveness_salvaged',
|
|
4250
|
+
JSON.stringify({
|
|
4251
|
+
runId: input.runId,
|
|
4252
|
+
runnerAttempt: suspension.runnerAttempt,
|
|
4253
|
+
sandboxId: suspension.sandboxId,
|
|
4254
|
+
exitCode: inspection.exitCode,
|
|
4255
|
+
diagnosis: inspection.diagnosis.stage,
|
|
4256
|
+
resultStatus: inspection.result.status,
|
|
4257
|
+
}),
|
|
4258
|
+
);
|
|
4259
|
+
return settleFirstWriteWinner(inspection.result);
|
|
4260
|
+
}
|
|
4261
|
+
if (inspection) {
|
|
4262
|
+
console.warn(
|
|
4263
|
+
'[absurd-runtime.worker] detached_runner_liveness_inspection_empty',
|
|
4264
|
+
JSON.stringify({
|
|
4265
|
+
runId: input.runId,
|
|
4266
|
+
runnerAttempt: suspension.runnerAttempt,
|
|
4267
|
+
sandboxId: suspension.sandboxId,
|
|
4268
|
+
exitCode: inspection.exitCode,
|
|
4269
|
+
diagnosis: inspection.diagnosis.stage,
|
|
4270
|
+
resultStatus: inspection.result?.status ?? null,
|
|
4271
|
+
}),
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
} catch (error) {
|
|
4275
|
+
console.warn(
|
|
4276
|
+
'[absurd-runtime.worker] detached_runner_liveness_inspection_failed',
|
|
4277
|
+
JSON.stringify({
|
|
4278
|
+
runId: input.runId,
|
|
4279
|
+
runnerAttempt: suspension.runnerAttempt,
|
|
4280
|
+
sandboxId: suspension.sandboxId,
|
|
4281
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4282
|
+
}),
|
|
4283
|
+
);
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4117
4286
|
return settleFirstWriteWinner({
|
|
4118
4287
|
status: 'failed',
|
|
4119
4288
|
error: `RUNTIME_RUNNER_LOST: Detached runner heartbeat expired after ${heartbeatAgeMs ?? 'unknown'}ms without a terminal result. Sandbox ${suspension.sandboxId}. The run was stopped and was not retried because provider side effects may already exist; completed row state remains persisted.`,
|
|
@@ -30,7 +30,7 @@ import { assertKnownResolvedBoundary } from '../checkpoint-boundaries';
|
|
|
30
30
|
import type { Absurd, Log, RetryStrategy } from '@deepline/absurd/sdk';
|
|
31
31
|
import { isIsolatedRuntimeSchedulerSchema } from '../runtime-scheduler-topology';
|
|
32
32
|
import {
|
|
33
|
-
|
|
33
|
+
assertAbsurdSchemaReady,
|
|
34
34
|
failPostgresSchedulerScheduledChildWaits,
|
|
35
35
|
type PostgresSchedulerWorkerOnceResult,
|
|
36
36
|
} from './postgres';
|
|
@@ -717,10 +717,12 @@ export function createAbsurdRuntimeClient(
|
|
|
717
717
|
const absurdReadyPromises = new Map<string, Promise<void>>();
|
|
718
718
|
|
|
719
719
|
/**
|
|
720
|
-
*
|
|
721
|
-
* schema and the shared queue with its
|
|
722
|
-
*
|
|
723
|
-
*
|
|
720
|
+
* Verify, once per process (keyed by pool url + schema), the deployment-owned
|
|
721
|
+
* Absurd schema contract and provision the shared queue with its policies.
|
|
722
|
+
* Schema DDL belongs exclusively to the migration gate: a worker or Vercel
|
|
723
|
+
* cold start may read this contract, but may never take the global bootstrap
|
|
724
|
+
* lock. The memoized promise is shared; a failure evicts the cache so the next
|
|
725
|
+
* caller retries loudly.
|
|
724
726
|
*/
|
|
725
727
|
export function ensureAbsurdRuntimeReady(
|
|
726
728
|
poolOptions: RuntimeSchedulerPoolOptions,
|
|
@@ -744,7 +746,7 @@ export function ensureAbsurdRuntimeReady(
|
|
|
744
746
|
if (existing) return existing;
|
|
745
747
|
const promise = (async () => {
|
|
746
748
|
await withRuntimeSchedulerClient(poolOptions, (client) =>
|
|
747
|
-
|
|
749
|
+
assertAbsurdSchemaReady(client),
|
|
748
750
|
);
|
|
749
751
|
// Hard-cutover cleanup: an old worker may have persisted a run waiting
|
|
750
752
|
// on a scheduled ctx.runPlay child. This runtime intentionally has no such
|