deepline 0.3.128 → 0.3.130
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/daytona-sandbox-janitor.ts +4 -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 +114 -4
- 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/absurd.ts +28 -8
- 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 +146 -15
- 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 +904 -77
- 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
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
PLAY_ADMISSION_MAX_ACQUIRE_QUEUE_WAIT_MS,
|
|
34
34
|
} from '../admission-transport-policy';
|
|
35
35
|
import { RUNTIME_RELIABILITY_POLICY } from '../runtime-reliability-policy';
|
|
36
|
+
import { RUNTIME_CAPACITY_POLICY } from '../runtime-capacity-policy';
|
|
36
37
|
export {
|
|
37
38
|
isRuntimeSchedulerCapacityError,
|
|
38
39
|
parseRuntimeSchedulerCapacityError,
|
|
@@ -126,8 +127,8 @@ export function assertRuntimeSchedulerHotPathUrl(url: string): void {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
export const RUNTIME_SCHEDULER_POOL_DEFAULTS = {
|
|
129
|
-
/**
|
|
130
|
-
maxClients:
|
|
130
|
+
/** One shared per-process client cap for scheduler control-plane lanes. */
|
|
131
|
+
maxClients: RUNTIME_CAPACITY_POLICY.runtimePostgres.schedulerPoolMaxClients,
|
|
131
132
|
/** Refuse to construct a pool above this — protects the shared PgBouncer/Postgres. */
|
|
132
133
|
maxClientsHardCap: 32,
|
|
133
134
|
/** Max time a caller waits for a pooled connection before erroring. */
|
|
@@ -163,7 +164,11 @@ export const RUNTIME_SCHEDULER_POOL_DEFAULTS = {
|
|
|
163
164
|
* once. This shared cap keeps horizontally scaled workers and the receipt
|
|
164
165
|
* gateway from consuming PgBouncer's global client budget independently.
|
|
165
166
|
*/
|
|
166
|
-
export const RUNTIME_SCHEDULER_CONTROL_PLANE_MAX_CLIENTS =
|
|
167
|
+
export const RUNTIME_SCHEDULER_CONTROL_PLANE_MAX_CLIENTS =
|
|
168
|
+
RUNTIME_CAPACITY_POLICY.runtimePostgres.schedulerPoolMaxClients;
|
|
169
|
+
|
|
170
|
+
export const RUNTIME_SCHEDULER_CANCEL_LOCK_TIMEOUT_MS = 2_000;
|
|
171
|
+
export const RUNTIME_SCHEDULER_CANCEL_STATEMENT_TIMEOUT_MS = 15_000;
|
|
167
172
|
|
|
168
173
|
export type RuntimeSchedulerPoolOptions = {
|
|
169
174
|
url: string;
|
|
@@ -188,6 +193,11 @@ export type RuntimeSchedulerPoolOptions = {
|
|
|
188
193
|
maxAcquireQueueWaitMs?: number;
|
|
189
194
|
};
|
|
190
195
|
|
|
196
|
+
export type RuntimeSchedulerOperationOptions = {
|
|
197
|
+
signal?: AbortSignal;
|
|
198
|
+
maxAttempts?: number;
|
|
199
|
+
};
|
|
200
|
+
|
|
191
201
|
export type RuntimeSchedulerQueryClient = {
|
|
192
202
|
query<Row extends Record<string, unknown> = Record<string, unknown>>(
|
|
193
203
|
sql: string,
|
|
@@ -195,6 +205,22 @@ export type RuntimeSchedulerQueryClient = {
|
|
|
195
205
|
): Promise<{ rows: Row[] }>;
|
|
196
206
|
};
|
|
197
207
|
|
|
208
|
+
export function isRuntimeSchedulerQueryCancellationError(
|
|
209
|
+
error: unknown,
|
|
210
|
+
): boolean {
|
|
211
|
+
if (!error || typeof error !== 'object') return false;
|
|
212
|
+
if ((error as { code?: unknown }).code === '57014') return true;
|
|
213
|
+
const name = (error as { name?: unknown }).name;
|
|
214
|
+
if (name === 'TimeoutError' || name === 'AbortError') return true;
|
|
215
|
+
const message = (error as { message?: unknown }).message;
|
|
216
|
+
return (
|
|
217
|
+
typeof message === 'string' &&
|
|
218
|
+
/(?:statement timeout|canceling statement due to user request|query read timeout)/i.test(
|
|
219
|
+
message,
|
|
220
|
+
)
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
198
224
|
export class RuntimeSchedulerCircuitOpenError extends Error {
|
|
199
225
|
readonly code = 'RUNTIME_SCHEDULER_UNAVAILABLE';
|
|
200
226
|
|
|
@@ -206,6 +232,47 @@ export class RuntimeSchedulerCircuitOpenError extends Error {
|
|
|
206
232
|
}
|
|
207
233
|
}
|
|
208
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Errors can cross the app/worker package boundary, where `instanceof` is not
|
|
237
|
+
* reliable. Keep this guard tied to the one canonical error name and message
|
|
238
|
+
* instead of making every status endpoint duplicate a string match.
|
|
239
|
+
*/
|
|
240
|
+
export function isRuntimeSchedulerCircuitOpenError(
|
|
241
|
+
error: unknown,
|
|
242
|
+
): error is RuntimeSchedulerCircuitOpenError {
|
|
243
|
+
if (error instanceof RuntimeSchedulerCircuitOpenError) return true;
|
|
244
|
+
return (
|
|
245
|
+
error instanceof Error &&
|
|
246
|
+
error.name === 'RuntimeSchedulerCircuitOpenError' &&
|
|
247
|
+
error.message.startsWith(
|
|
248
|
+
'Runtime scheduler DB circuit breaker is open after repeated connection failures:',
|
|
249
|
+
)
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
type SchedulerCircuitWait = (delayMs: number) => Promise<void>;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Give the existing scheduler-pool breaker one half-open trial before an
|
|
257
|
+
* idempotent control-plane read is surfaced as unavailable. This is not a
|
|
258
|
+
* second retry policy or congestion controller: it waits exactly the breaker
|
|
259
|
+
* cooldown already enforced by `withRuntimeSchedulerClient`, retries once,
|
|
260
|
+
* and only accepts read operations supplied by the caller.
|
|
261
|
+
*/
|
|
262
|
+
export async function retryOnceAfterRuntimeSchedulerCircuitOpen<T>(
|
|
263
|
+
read: () => Promise<T>,
|
|
264
|
+
options: { wait?: SchedulerCircuitWait } = {},
|
|
265
|
+
): Promise<T> {
|
|
266
|
+
try {
|
|
267
|
+
return await read();
|
|
268
|
+
} catch (error) {
|
|
269
|
+
if (!isRuntimeSchedulerCircuitOpenError(error)) throw error;
|
|
270
|
+
const wait = options.wait ?? sleep;
|
|
271
|
+
await wait(RUNTIME_SCHEDULER_POOL_DEFAULTS.breaker.openMs);
|
|
272
|
+
return read();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
209
276
|
type LatencyRing = {
|
|
210
277
|
samples: number[];
|
|
211
278
|
next: number;
|
|
@@ -697,11 +764,21 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
697
764
|
phase: string;
|
|
698
765
|
priority?: RuntimeSchedulerPoolPriority;
|
|
699
766
|
},
|
|
700
|
-
operationOptions:
|
|
767
|
+
operationOptions: RuntimeSchedulerOperationOptions = {},
|
|
701
768
|
): Promise<T> {
|
|
702
769
|
const signal = operationOptions.signal;
|
|
703
770
|
throwIfSchedulerAborted(signal);
|
|
704
771
|
const entry = getPoolEntry(options);
|
|
772
|
+
const maxAttempts = Math.max(
|
|
773
|
+
1,
|
|
774
|
+
Math.min(
|
|
775
|
+
RUNTIME_SCHEDULER_POOL_DEFAULTS.retry.attempts,
|
|
776
|
+
Math.floor(
|
|
777
|
+
operationOptions.maxAttempts ??
|
|
778
|
+
RUNTIME_SCHEDULER_POOL_DEFAULTS.retry.attempts,
|
|
779
|
+
),
|
|
780
|
+
),
|
|
781
|
+
);
|
|
705
782
|
const operationStartedAt = performance.now();
|
|
706
783
|
const admissionStartedAt = performance.now();
|
|
707
784
|
const releaseAdmission = await entry.admission.acquire(
|
|
@@ -712,11 +789,7 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
712
789
|
let lastError: unknown = null;
|
|
713
790
|
try {
|
|
714
791
|
throwIfSchedulerAborted(signal);
|
|
715
|
-
for (
|
|
716
|
-
let attempt = 0;
|
|
717
|
-
attempt < RUNTIME_SCHEDULER_POOL_DEFAULTS.retry.attempts;
|
|
718
|
-
attempt += 1
|
|
719
|
-
) {
|
|
792
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
720
793
|
throwIfSchedulerAborted(signal);
|
|
721
794
|
breakerGate(entry);
|
|
722
795
|
if (entry.pool.waitingCount >= entry.maxAcquireQueueDepth) {
|
|
@@ -755,7 +828,7 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
755
828
|
recordBreakerFailure(entry, error);
|
|
756
829
|
entry.stats.connectionErrors += 1;
|
|
757
830
|
lastError = error;
|
|
758
|
-
if (attempt + 1 <
|
|
831
|
+
if (attempt + 1 < maxAttempts) {
|
|
759
832
|
entry.stats.retries += 1;
|
|
760
833
|
await sleep(jitteredBackoffMs(attempt));
|
|
761
834
|
throwIfSchedulerAborted(signal);
|
|
@@ -805,9 +878,18 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
805
878
|
const queryStartedAt = performance.now();
|
|
806
879
|
queryCount += 1;
|
|
807
880
|
try {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
881
|
+
try {
|
|
882
|
+
const queryResult = await poolClient.query(sql, params);
|
|
883
|
+
throwIfSchedulerAborted(signal);
|
|
884
|
+
return { rows: queryResult.rows };
|
|
885
|
+
} catch (error) {
|
|
886
|
+
if (isRuntimeSchedulerQueryCancellationError(error)) {
|
|
887
|
+
releasePoolClient(
|
|
888
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
throw error;
|
|
892
|
+
}
|
|
811
893
|
} finally {
|
|
812
894
|
queryMs += performance.now() - queryStartedAt;
|
|
813
895
|
}
|
|
@@ -873,6 +955,14 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
873
955
|
error instanceof Error ? error.message : String(error),
|
|
874
956
|
);
|
|
875
957
|
}
|
|
958
|
+
if (isRuntimeSchedulerQueryCancellationError(error)) {
|
|
959
|
+
entry.stats.queryErrors += 1;
|
|
960
|
+
recordBreakerSuccess(entry);
|
|
961
|
+
releasePoolClient(
|
|
962
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
963
|
+
);
|
|
964
|
+
throw error;
|
|
965
|
+
}
|
|
876
966
|
if (isConnectionCategoryError(error)) {
|
|
877
967
|
recordBreakerFailure(entry, error);
|
|
878
968
|
entry.stats.connectionErrors += 1;
|
|
@@ -881,7 +971,7 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
881
971
|
releasePoolClient(
|
|
882
972
|
error instanceof Error ? error : new Error(String(error)),
|
|
883
973
|
);
|
|
884
|
-
if (attempt + 1 <
|
|
974
|
+
if (attempt + 1 < maxAttempts) {
|
|
885
975
|
entry.stats.retries += 1;
|
|
886
976
|
await sleep(jitteredBackoffMs(attempt));
|
|
887
977
|
throwIfSchedulerAborted(signal);
|
|
@@ -899,7 +989,7 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
899
989
|
releasePoolClient(
|
|
900
990
|
error instanceof Error ? error : new Error(String(error)),
|
|
901
991
|
);
|
|
902
|
-
if (attempt + 1 <
|
|
992
|
+
if (attempt + 1 < maxAttempts) {
|
|
903
993
|
entry.stats.retries += 1;
|
|
904
994
|
await sleep(jitteredBackoffMs(attempt));
|
|
905
995
|
throwIfSchedulerAborted(signal);
|
|
@@ -923,6 +1013,47 @@ export async function withRuntimeSchedulerClient<T>(
|
|
|
923
1013
|
}
|
|
924
1014
|
}
|
|
925
1015
|
|
|
1016
|
+
export async function withRuntimeSchedulerTransaction<T>(
|
|
1017
|
+
options: RuntimeSchedulerPoolOptions,
|
|
1018
|
+
timeouts: { lockTimeoutMs: number; statementTimeoutMs: number },
|
|
1019
|
+
fn: (client: RuntimeSchedulerQueryClient) => Promise<T>,
|
|
1020
|
+
trace?: {
|
|
1021
|
+
runId: string;
|
|
1022
|
+
phase: string;
|
|
1023
|
+
priority?: RuntimeSchedulerPoolPriority;
|
|
1024
|
+
},
|
|
1025
|
+
operationOptions: RuntimeSchedulerOperationOptions = {},
|
|
1026
|
+
): Promise<T> {
|
|
1027
|
+
const lockTimeoutMs = Math.max(1, Math.floor(timeouts.lockTimeoutMs));
|
|
1028
|
+
const statementTimeoutMs = Math.max(
|
|
1029
|
+
lockTimeoutMs,
|
|
1030
|
+
Math.floor(timeouts.statementTimeoutMs),
|
|
1031
|
+
);
|
|
1032
|
+
return withRuntimeSchedulerClient(
|
|
1033
|
+
options,
|
|
1034
|
+
async (client) => {
|
|
1035
|
+
await client.query('BEGIN');
|
|
1036
|
+
try {
|
|
1037
|
+
await client.query(
|
|
1038
|
+
`SELECT set_config('lock_timeout', $1, true),
|
|
1039
|
+
set_config('statement_timeout', $2, true)`,
|
|
1040
|
+
[`${lockTimeoutMs}ms`, `${statementTimeoutMs}ms`],
|
|
1041
|
+
);
|
|
1042
|
+
const result = await fn(client);
|
|
1043
|
+
await client.query('COMMIT');
|
|
1044
|
+
return result;
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
if (!isRuntimeSchedulerQueryCancellationError(error)) {
|
|
1047
|
+
await client.query('ROLLBACK').catch(() => undefined);
|
|
1048
|
+
}
|
|
1049
|
+
throw error;
|
|
1050
|
+
}
|
|
1051
|
+
},
|
|
1052
|
+
trace,
|
|
1053
|
+
{ ...operationOptions, maxAttempts: operationOptions.maxAttempts ?? 1 },
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
926
1057
|
export type RuntimeSchedulerPoolStats = {
|
|
927
1058
|
url: string;
|
|
928
1059
|
maxClients: number;
|
package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts
CHANGED
|
@@ -19,12 +19,18 @@ import {
|
|
|
19
19
|
} from '../app-runtime-api';
|
|
20
20
|
import type { PlayVisualNodeProgressMap } from '../worker-api-types';
|
|
21
21
|
import type { PlayExecutionEvent } from '../ctx-types';
|
|
22
|
+
import type { PlayActivityObservation } from '../activity-observation';
|
|
22
23
|
import type {
|
|
23
24
|
PlayRunnerLogEvent,
|
|
24
25
|
PlayRunnerResult,
|
|
25
26
|
} from '../protocol';
|
|
26
27
|
import type { PlaySchedulerSubmitInput } from '../scheduler-backend';
|
|
27
28
|
import type { DocflowObservationRecord } from '../docflow-observation';
|
|
29
|
+
import {
|
|
30
|
+
buildPlayRunLedgerEventsFromStatusPatch,
|
|
31
|
+
createEmptyPlayRunLedgerSnapshot,
|
|
32
|
+
type PlayRunLedgerEvent,
|
|
33
|
+
} from '../run-ledger';
|
|
28
34
|
import {
|
|
29
35
|
getTopLevelPipelineSubsteps,
|
|
30
36
|
type PlayStaticPipeline,
|
|
@@ -248,7 +254,16 @@ function shouldPublishTerminalResultLog(
|
|
|
248
254
|
mode: PostgresSchedulerDurableLogMode,
|
|
249
255
|
line: string,
|
|
250
256
|
): boolean {
|
|
251
|
-
|
|
257
|
+
// Direct workers keep host lifecycle noise out of the customer Run Log
|
|
258
|
+
// Stream. The resource summary is one bounded, machine-readable terminal
|
|
259
|
+
// diagnostic rather than a host log, though: the fixture harness needs it
|
|
260
|
+
// after the runner has gone away and the normal terminal result is no longer
|
|
261
|
+
// available through the status projection.
|
|
262
|
+
return (
|
|
263
|
+
mode !== 'direct_worker' ||
|
|
264
|
+
CTX_LOG_TIMESTAMP_PREFIX_RE.test(line) ||
|
|
265
|
+
line.startsWith('[runtime.phase_summary] ')
|
|
266
|
+
);
|
|
252
267
|
}
|
|
253
268
|
|
|
254
269
|
type TerminalLogReplayPayload = NonNullable<
|
|
@@ -323,14 +338,34 @@ export function createPostgresSchedulerProgressReporter(input: {
|
|
|
323
338
|
durableLogMode?: PostgresSchedulerDurableLogMode;
|
|
324
339
|
producerAttempt?: number;
|
|
325
340
|
isCurrentAttempt?: () => boolean | Promise<boolean>;
|
|
341
|
+
/**
|
|
342
|
+
* The caller already read the durable attempt fence for THIS request and it
|
|
343
|
+
* was current. The first projection flush then reuses that read instead of
|
|
344
|
+
* paying a second identical round trip. A reporter lives for exactly one
|
|
345
|
+
* request, and the credit is consumed by the first flush, so a later flush —
|
|
346
|
+
* and every other request — re-reads the fence.
|
|
347
|
+
*/
|
|
348
|
+
attemptAlreadyVerified?: boolean;
|
|
326
349
|
/** Durable log position before this reporter's first event. Push runners own
|
|
327
350
|
* this cursor so successive batches may land on different gateway Machines. */
|
|
328
351
|
initialLiveLogTotalCount?: number;
|
|
352
|
+
/** Override the app-runtime transport when a caller needs to capture the
|
|
353
|
+
* folded terminal patch for a durable scheduler outbox instead of posting
|
|
354
|
+
* it synchronously. */
|
|
355
|
+
publishStatusUpdate?: (update: RuntimeStatusUpdate) => Promise<void>;
|
|
329
356
|
}): PostgresSchedulerProgressReporter {
|
|
330
357
|
const launch = input.launch;
|
|
331
358
|
const durableLogMode = input.durableLogMode ?? 'progress_reporter';
|
|
332
359
|
const producerAttempt = input.producerAttempt;
|
|
333
|
-
const
|
|
360
|
+
const readAttemptFence = input.isCurrentAttempt ?? (() => true);
|
|
361
|
+
let verifiedAttemptCredit = input.attemptAlreadyVerified === true;
|
|
362
|
+
const isCurrentAttempt = async (): Promise<boolean> => {
|
|
363
|
+
if (verifiedAttemptCredit) {
|
|
364
|
+
verifiedAttemptCredit = false;
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
return await readAttemptFence();
|
|
368
|
+
};
|
|
334
369
|
const orderedNodes = buildOrderedNodeList(launch.contractSnapshot);
|
|
335
370
|
const mapNodeLookup = buildMapNodeLookup(launch.contractSnapshot);
|
|
336
371
|
const runtimeApi = {
|
|
@@ -338,6 +373,10 @@ export function createPostgresSchedulerProgressReporter(input: {
|
|
|
338
373
|
executorToken: launch.executorToken,
|
|
339
374
|
vercelProtectionBypassToken: launch.vercelProtectionBypassToken ?? null,
|
|
340
375
|
};
|
|
376
|
+
const publishStatusUpdate =
|
|
377
|
+
input.publishStatusUpdate ??
|
|
378
|
+
((update: RuntimeStatusUpdate) =>
|
|
379
|
+
updateRunStatusViaAppRuntime(runtimeApi, update));
|
|
341
380
|
|
|
342
381
|
let liveNodeProgress: PlayVisualNodeProgressMap = {};
|
|
343
382
|
let liveNodeProgressDirty = false;
|
|
@@ -427,7 +466,7 @@ export function createPostgresSchedulerProgressReporter(input: {
|
|
|
427
466
|
|
|
428
467
|
try {
|
|
429
468
|
if (await isCurrentAttempt()) {
|
|
430
|
-
await
|
|
469
|
+
await publishStatusUpdate({
|
|
431
470
|
playId: launch.runId,
|
|
432
471
|
status: request.status,
|
|
433
472
|
liveNodeProgress: nextProgress,
|
|
@@ -1246,10 +1285,102 @@ export const createDirectWorkerProgressReporter = (input: {
|
|
|
1246
1285
|
launch: PlaySchedulerSubmitInput;
|
|
1247
1286
|
producerAttempt?: number;
|
|
1248
1287
|
isCurrentAttempt?: () => boolean | Promise<boolean>;
|
|
1288
|
+
/** See `createPostgresSchedulerProgressReporter`: one request, one credit. */
|
|
1289
|
+
attemptAlreadyVerified?: boolean;
|
|
1249
1290
|
initialLiveLogTotalCount?: number;
|
|
1291
|
+
publishStatusUpdate?: (update: RuntimeStatusUpdate) => Promise<void>;
|
|
1250
1292
|
}) =>
|
|
1251
1293
|
createPostgresSchedulerProgressReporter({
|
|
1252
1294
|
...input,
|
|
1253
1295
|
durableLogMode: 'direct_worker',
|
|
1254
1296
|
});
|
|
1255
1297
|
export type DirectWorkerProgressReporter = PostgresSchedulerProgressReporter;
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Fold a detached runner's final progress without crossing the app-runtime
|
|
1301
|
+
* network boundary. The returned events are stored in the same Postgres
|
|
1302
|
+
* terminal outbox row as `run.completed`, so the projector can append the
|
|
1303
|
+
* final step/log/activity facts and the terminal fact in one ordered Convex
|
|
1304
|
+
* mutation. This is the completed-run fast path; failed/suspended runs retain
|
|
1305
|
+
* the compatibility projection until their parked worker resumes.
|
|
1306
|
+
*/
|
|
1307
|
+
export async function collectGatewayRunnerTerminalProgressLedgerEvents(input: {
|
|
1308
|
+
launch: PlaySchedulerSubmitInput;
|
|
1309
|
+
attempt: number;
|
|
1310
|
+
result: PlayRunnerResult;
|
|
1311
|
+
events: unknown[];
|
|
1312
|
+
liveLogOffset: number;
|
|
1313
|
+
}): Promise<PlayRunLedgerEvent[]> {
|
|
1314
|
+
const captured: { update?: RuntimeStatusUpdate } = {};
|
|
1315
|
+
const reporter = createDirectWorkerProgressReporter({
|
|
1316
|
+
launch: input.launch,
|
|
1317
|
+
producerAttempt: input.attempt,
|
|
1318
|
+
initialLiveLogTotalCount: input.liveLogOffset,
|
|
1319
|
+
isCurrentAttempt: () => true,
|
|
1320
|
+
attemptAlreadyVerified: true,
|
|
1321
|
+
publishStatusUpdate: async (update) => {
|
|
1322
|
+
captured.update = update;
|
|
1323
|
+
},
|
|
1324
|
+
});
|
|
1325
|
+
for (const event of input.events) reporter.onRunnerEvent(event);
|
|
1326
|
+
await reporter.finalize(input.result, {
|
|
1327
|
+
status: 'running',
|
|
1328
|
+
required: true,
|
|
1329
|
+
skipTerminalLogReplay: true,
|
|
1330
|
+
terminalLogProducerAttempt: input.attempt,
|
|
1331
|
+
});
|
|
1332
|
+
const finalUpdate = captured.update;
|
|
1333
|
+
if (!finalUpdate) return [];
|
|
1334
|
+
|
|
1335
|
+
const liveLogs = finalUpdate.liveLogs ?? [];
|
|
1336
|
+
const liveLogTotalCount =
|
|
1337
|
+
finalUpdate.liveLogTotalCount ?? liveLogs.length + input.liveLogOffset;
|
|
1338
|
+
const progressEvents = buildPlayRunLedgerEventsFromStatusPatch({
|
|
1339
|
+
patch: {
|
|
1340
|
+
runId: input.launch.runId,
|
|
1341
|
+
status: 'running',
|
|
1342
|
+
lastCheckpointAt: finalUpdate.lastCheckpointAt,
|
|
1343
|
+
liveNodeProgress: finalUpdate.liveNodeProgress,
|
|
1344
|
+
liveLogs,
|
|
1345
|
+
liveLogsChannelOffset: Math.max(0, liveLogTotalCount - liveLogs.length),
|
|
1346
|
+
liveLogsProducerAttempt:
|
|
1347
|
+
finalUpdate.liveLogProducerAttempt ?? input.attempt,
|
|
1348
|
+
},
|
|
1349
|
+
previousSnapshot: createEmptyPlayRunLedgerSnapshot({
|
|
1350
|
+
runId: input.launch.runId,
|
|
1351
|
+
status: 'queued',
|
|
1352
|
+
}),
|
|
1353
|
+
source: 'worker',
|
|
1354
|
+
});
|
|
1355
|
+
const datasetEvents: PlayRunLedgerEvent[] = (
|
|
1356
|
+
finalUpdate.datasetLifecycleEvents ?? []
|
|
1357
|
+
).map((event) => ({
|
|
1358
|
+
type: 'dataset.lifecycle',
|
|
1359
|
+
runId: input.launch.runId,
|
|
1360
|
+
source: 'worker',
|
|
1361
|
+
occurredAt: event.at,
|
|
1362
|
+
datasetId: event.datasetId,
|
|
1363
|
+
path: event.path,
|
|
1364
|
+
tableNamespace: event.tableNamespace,
|
|
1365
|
+
phase: event.phase,
|
|
1366
|
+
...(event.persistedRows === undefined
|
|
1367
|
+
? {}
|
|
1368
|
+
: { persistedRows: event.persistedRows }),
|
|
1369
|
+
...(event.succeededRows === undefined
|
|
1370
|
+
? {}
|
|
1371
|
+
: { succeededRows: event.succeededRows }),
|
|
1372
|
+
...(event.failedRows === undefined ? {} : { failedRows: event.failedRows }),
|
|
1373
|
+
...(event.complete === undefined ? {} : { complete: event.complete }),
|
|
1374
|
+
...(event.bornFrom === undefined ? {} : { bornFrom: event.bornFrom }),
|
|
1375
|
+
}));
|
|
1376
|
+
const activityEvents: PlayRunLedgerEvent[] = (
|
|
1377
|
+
finalUpdate.activityObservations ?? []
|
|
1378
|
+
).map((observation: PlayActivityObservation) => ({
|
|
1379
|
+
type: 'activity.observed',
|
|
1380
|
+
runId: input.launch.runId,
|
|
1381
|
+
source: 'worker',
|
|
1382
|
+
occurredAt: observation.observedAt,
|
|
1383
|
+
observation,
|
|
1384
|
+
}));
|
|
1385
|
+
return [...progressEvents, ...datasetEvents, ...activityEvents];
|
|
1386
|
+
}
|