deepline 0.3.235 → 0.3.237
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 +6 -0
- package/dist/bundling-sources/sdk/src/http.ts +46 -10
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +26 -7
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +299 -130
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +219 -46
- package/dist/cli/index.js +184 -56
- package/dist/cli/index.mjs +184 -56
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +37 -4
- package/dist/index.mjs +37 -4
- 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
|
@@ -6858,7 +6858,7 @@ export async function assignPostgresSchedulerRunAttempt(
|
|
|
6858
6858
|
*/
|
|
6859
6859
|
export async function resumePostgresSchedulerDetachedRunnerAttempt(
|
|
6860
6860
|
client: PostgresSchedulerQueryClient,
|
|
6861
|
-
input: { runId: string },
|
|
6861
|
+
input: { runId: string; attempt?: number; leaseToken?: string },
|
|
6862
6862
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
6863
6863
|
): Promise<{
|
|
6864
6864
|
attempt: number;
|
|
@@ -6873,27 +6873,77 @@ export async function resumePostgresSchedulerDetachedRunnerAttempt(
|
|
|
6873
6873
|
suspension_json: unknown;
|
|
6874
6874
|
}>(
|
|
6875
6875
|
`
|
|
6876
|
-
WITH
|
|
6877
|
-
SELECT run_id, checkpoint_json, suspension_json
|
|
6876
|
+
WITH detached_run AS MATERIALIZED (
|
|
6877
|
+
SELECT run_id, status, checkpoint_json, suspension_json
|
|
6878
6878
|
FROM ${tableName('runs', options)}
|
|
6879
6879
|
WHERE run_id = $1
|
|
6880
|
-
AND status
|
|
6880
|
+
AND status IN ('running', 'waiting')
|
|
6881
6881
|
AND suspension_json ->> 'kind' = 'detached_runner'
|
|
6882
|
+
AND NOT EXISTS (
|
|
6883
|
+
SELECT 1 FROM ${tableName('control', options)} AS control
|
|
6884
|
+
WHERE control.key = 'runtime_cancel:' || $1
|
|
6885
|
+
)
|
|
6882
6886
|
FOR UPDATE
|
|
6887
|
+
), detached_attempt AS MATERIALIZED (
|
|
6888
|
+
SELECT attempt.run_id, attempt.attempt, attempt.status, attempt.lease_token
|
|
6889
|
+
FROM ${tableName('attempts', options)} AS attempt
|
|
6890
|
+
JOIN detached_run ON attempt.run_id = detached_run.run_id
|
|
6891
|
+
WHERE attempt.attempt = (detached_run.suspension_json ->> 'runnerAttempt')::integer
|
|
6892
|
+
AND attempt.status IN ('running', 'waiting')
|
|
6893
|
+
AND attempt.lease_token IS NOT NULL
|
|
6894
|
+
AND ($2::integer IS NULL OR attempt.attempt = $2)
|
|
6895
|
+
AND ($3::text IS NULL OR attempt.lease_token = $3)
|
|
6896
|
+
AND NOT EXISTS (
|
|
6897
|
+
SELECT 1 FROM ${tableName('attempts', options)} AS newer
|
|
6898
|
+
WHERE newer.run_id = attempt.run_id AND newer.attempt > attempt.attempt
|
|
6899
|
+
AND newer.status IN ('claimed', 'running', 'waiting', 'completed', 'failed')
|
|
6900
|
+
)
|
|
6901
|
+
FOR UPDATE OF attempt
|
|
6902
|
+
), restored_attempt AS (
|
|
6903
|
+
UPDATE ${tableName('attempts', options)} AS target
|
|
6904
|
+
SET status = 'waiting', updated_at = now()
|
|
6905
|
+
FROM detached_attempt
|
|
6906
|
+
WHERE target.run_id = detached_attempt.run_id
|
|
6907
|
+
AND target.attempt = detached_attempt.attempt
|
|
6908
|
+
AND target.lease_token = detached_attempt.lease_token
|
|
6909
|
+
AND target.status = 'running'
|
|
6910
|
+
RETURNING target.run_id
|
|
6911
|
+
), restored_run AS (
|
|
6912
|
+
UPDATE ${tableName('runs', options)} AS target
|
|
6913
|
+
SET status = 'waiting',
|
|
6914
|
+
wait_deadline = CASE
|
|
6915
|
+
WHEN jsonb_typeof(target.suspension_json -> 'startedAtMs') = 'number'
|
|
6916
|
+
AND jsonb_typeof(target.suspension_json -> 'ceilingMs') = 'number'
|
|
6917
|
+
THEN to_timestamp(
|
|
6918
|
+
((target.suspension_json ->> 'startedAtMs')::double precision +
|
|
6919
|
+
(target.suspension_json ->> 'ceilingMs')::double precision) / 1000
|
|
6920
|
+
) ELSE target.wait_deadline END,
|
|
6921
|
+
updated_at = now()
|
|
6922
|
+
WHERE target.run_id IN (SELECT run_id FROM detached_attempt)
|
|
6923
|
+
AND target.status = 'running'
|
|
6924
|
+
RETURNING target.run_id
|
|
6925
|
+
), restored_outbox AS (
|
|
6926
|
+
INSERT INTO ${tableName('outbox', options)} (
|
|
6927
|
+
event_id, run_id, event_type, payload_json, created_at
|
|
6928
|
+
)
|
|
6929
|
+
SELECT $4, run_id, 'run.waiting', jsonb_build_object('kind', 'detached_runner'),
|
|
6930
|
+
${causalOutboxCreatedAt('restored_run.run_id', options)}
|
|
6931
|
+
FROM restored_run
|
|
6932
|
+
RETURNING run_id
|
|
6883
6933
|
)
|
|
6884
|
-
SELECT
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
waiting_run.suspension_json
|
|
6888
|
-
FROM ${tableName('attempts', options)} AS attempts
|
|
6889
|
-
JOIN waiting_run ON attempts.run_id = waiting_run.run_id
|
|
6890
|
-
WHERE attempts.attempt = (waiting_run.suspension_json ->> 'runnerAttempt')::integer
|
|
6891
|
-
AND attempts.status = 'waiting'
|
|
6934
|
+
SELECT detached_attempt.attempt, detached_attempt.lease_token,
|
|
6935
|
+
detached_run.checkpoint_json, detached_run.suspension_json
|
|
6936
|
+
FROM detached_attempt JOIN detached_run USING (run_id)
|
|
6892
6937
|
`,
|
|
6893
|
-
[
|
|
6938
|
+
[
|
|
6939
|
+
input.runId,
|
|
6940
|
+
input.attempt ?? null,
|
|
6941
|
+
input.leaseToken ?? null,
|
|
6942
|
+
`run-waiting:${input.runId}:${randomUUID()}`,
|
|
6943
|
+
],
|
|
6894
6944
|
);
|
|
6895
6945
|
const row = resumed.rows[0];
|
|
6896
|
-
if (!row
|
|
6946
|
+
if (!row) return null;
|
|
6897
6947
|
return {
|
|
6898
6948
|
attempt: Number(row.attempt),
|
|
6899
6949
|
leaseToken: row.lease_token,
|
|
@@ -6902,6 +6952,33 @@ export async function resumePostgresSchedulerDetachedRunnerAttempt(
|
|
|
6902
6952
|
};
|
|
6903
6953
|
}
|
|
6904
6954
|
|
|
6955
|
+
/** A worker error cannot settle/release an execution owned by the detached
|
|
6956
|
+
* runner, including one whose authoritative result is waiting to be reduced. */
|
|
6957
|
+
export async function hasPostgresSchedulerRecoverableDetachedRunner(
|
|
6958
|
+
client: PostgresSchedulerQueryClient,
|
|
6959
|
+
input: { runId: string; attempt: number; leaseToken: string },
|
|
6960
|
+
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
6961
|
+
): Promise<boolean> {
|
|
6962
|
+
const result = await client.query<{ recoverable: boolean }>(
|
|
6963
|
+
`SELECT EXISTS (
|
|
6964
|
+
SELECT 1 FROM ${tableName('runs', options)} AS run
|
|
6965
|
+
JOIN ${tableName('attempts', options)} AS attempt ON attempt.run_id = run.run_id
|
|
6966
|
+
WHERE run.run_id = $1 AND attempt.attempt = $2 AND attempt.lease_token = $3
|
|
6967
|
+
AND run.status IN ('running', 'waiting')
|
|
6968
|
+
AND run.suspension_json ->> 'kind' = 'detached_runner'
|
|
6969
|
+
AND run.suspension_json -> 'runnerAttempt' = to_jsonb(attempt.attempt)
|
|
6970
|
+
AND attempt.status IN ('running', 'waiting')
|
|
6971
|
+
AND NOT EXISTS (SELECT 1 FROM ${tableName('control', options)} AS control
|
|
6972
|
+
WHERE control.key = 'runtime_cancel:' || run.run_id)
|
|
6973
|
+
AND NOT EXISTS (SELECT 1 FROM ${tableName('attempts', options)} AS newer
|
|
6974
|
+
WHERE newer.run_id = run.run_id AND newer.attempt > attempt.attempt
|
|
6975
|
+
AND newer.status IN ('claimed', 'running', 'waiting', 'completed', 'failed'))
|
|
6976
|
+
) AS recoverable`,
|
|
6977
|
+
[input.runId, input.attempt, input.leaseToken],
|
|
6978
|
+
);
|
|
6979
|
+
return result.rows[0]?.recoverable === true;
|
|
6980
|
+
}
|
|
6981
|
+
|
|
6905
6982
|
export async function markPostgresSchedulerAttemptWaiting(
|
|
6906
6983
|
client: PostgresSchedulerQueryClient,
|
|
6907
6984
|
input: {
|
|
@@ -7087,7 +7164,9 @@ export async function markPostgresSchedulerAttemptRunning(
|
|
|
7087
7164
|
running_run AS (
|
|
7088
7165
|
UPDATE ${tableName('runs', options)} AS target
|
|
7089
7166
|
SET status = 'running',
|
|
7090
|
-
suspension_json =
|
|
7167
|
+
suspension_json = CASE
|
|
7168
|
+
WHEN $5::boolean AND target.suspension_json ->> 'kind' = 'detached_runner'
|
|
7169
|
+
THEN target.suspension_json ELSE NULL END,
|
|
7091
7170
|
wait_deadline = NULL,
|
|
7092
7171
|
updated_at = now()
|
|
7093
7172
|
FROM waiting_run
|
|
@@ -7263,7 +7342,7 @@ export async function claimPostgresSchedulerOverdueDetachedRunnerCeilings(
|
|
|
7263
7342
|
JOIN ${tableName('attempts', options)} AS attempts
|
|
7264
7343
|
ON attempts.run_id = runs.run_id
|
|
7265
7344
|
AND attempts.attempt = (runs.suspension_json ->> 'runnerAttempt')::integer
|
|
7266
|
-
WHERE runs.status
|
|
7345
|
+
WHERE runs.status IN ('running', 'waiting')
|
|
7267
7346
|
AND runs.suspension_json ->> 'kind' = 'detached_runner'
|
|
7268
7347
|
AND COALESCE(
|
|
7269
7348
|
runs.wait_deadline,
|
|
@@ -7277,7 +7356,7 @@ export async function claimPostgresSchedulerOverdueDetachedRunnerCeilings(
|
|
|
7277
7356
|
ELSE NULL
|
|
7278
7357
|
END
|
|
7279
7358
|
) <= clock_timestamp()
|
|
7280
|
-
AND attempts.status
|
|
7359
|
+
AND attempts.status IN ('running', 'waiting')
|
|
7281
7360
|
AND attempts.lease_token IS NOT NULL
|
|
7282
7361
|
AND (
|
|
7283
7362
|
attempts.runner_result_json IS NULL
|
|
@@ -7317,7 +7396,7 @@ export async function claimPostgresSchedulerOverdueDetachedRunnerCeilings(
|
|
|
7317
7396
|
FROM candidates
|
|
7318
7397
|
WHERE target.run_id = candidates.run_id
|
|
7319
7398
|
AND target.attempt = candidates.attempt
|
|
7320
|
-
AND target.status
|
|
7399
|
+
AND target.status IN ('running', 'waiting')
|
|
7321
7400
|
AND target.lease_token IS NOT NULL
|
|
7322
7401
|
AND (
|
|
7323
7402
|
target.runner_result_json IS NULL
|
|
@@ -7328,12 +7407,13 @@ export async function claimPostgresSchedulerOverdueDetachedRunnerCeilings(
|
|
|
7328
7407
|
running_runs AS (
|
|
7329
7408
|
UPDATE ${tableName('runs', options)} AS target
|
|
7330
7409
|
SET status = 'running',
|
|
7331
|
-
|
|
7332
|
-
|
|
7410
|
+
-- A controller can disappear between this claim and the terminal
|
|
7411
|
+
-- write. Retain the detached snapshot and ceiling so its successor
|
|
7412
|
+
-- can reclaim the same fenced obligation without restarting code.
|
|
7333
7413
|
updated_at = now()
|
|
7334
7414
|
FROM running_attempts
|
|
7335
7415
|
WHERE target.run_id = running_attempts.run_id
|
|
7336
|
-
AND target.status
|
|
7416
|
+
AND target.status IN ('running', 'waiting')
|
|
7337
7417
|
RETURNING target.run_id
|
|
7338
7418
|
),
|
|
7339
7419
|
resumed_outbox AS (
|
|
@@ -10573,6 +10653,73 @@ export async function completePostgresSchedulerComputeBillingSessionBootstrap(
|
|
|
10573
10653
|
return completed.rows.length > 0;
|
|
10574
10654
|
}
|
|
10575
10655
|
|
|
10656
|
+
/** Deletion needs terminal/cancellation/retired-resource authority. An old
|
|
10657
|
+
* worker error (including a billing end) is not evidence the runner stopped. */
|
|
10658
|
+
function protectedDetachedSandboxSql(
|
|
10659
|
+
identity: {
|
|
10660
|
+
runId: string;
|
|
10661
|
+
provider: string;
|
|
10662
|
+
sandboxId: string;
|
|
10663
|
+
routingDomain: string;
|
|
10664
|
+
},
|
|
10665
|
+
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
10666
|
+
): string {
|
|
10667
|
+
return `EXISTS (
|
|
10668
|
+
SELECT 1 FROM ${tableName('runs', options)} AS detached_run
|
|
10669
|
+
JOIN ${tableName('attempts', options)} AS detached_attempt
|
|
10670
|
+
ON detached_attempt.run_id = detached_run.run_id
|
|
10671
|
+
CROSS JOIN LATERAL jsonb_array_elements(
|
|
10672
|
+
CASE WHEN jsonb_typeof(detached_attempt.resource_json) = 'array'
|
|
10673
|
+
THEN detached_attempt.resource_json
|
|
10674
|
+
WHEN detached_attempt.resource_json IS NULL THEN '[]'::jsonb
|
|
10675
|
+
ELSE jsonb_build_array(detached_attempt.resource_json) END
|
|
10676
|
+
) AS detached_resource
|
|
10677
|
+
WHERE detached_run.run_id = ${identity.runId}
|
|
10678
|
+
AND detached_run.status IN ('running', 'waiting')
|
|
10679
|
+
AND detached_attempt.status IN ('claimed', 'running', 'waiting')
|
|
10680
|
+
AND detached_attempt.runner_result_json IS NULL
|
|
10681
|
+
AND detached_resource ->> 'sandboxId' = ${identity.sandboxId}
|
|
10682
|
+
AND CASE detached_resource ->> 'kind'
|
|
10683
|
+
WHEN 'daytona_sandbox' THEN 'daytona'
|
|
10684
|
+
WHEN 'modal_sandbox' THEN 'modal' END = ${identity.provider}
|
|
10685
|
+
AND (CASE detached_resource ->> 'kind'
|
|
10686
|
+
WHEN 'modal_sandbox' THEN NULLIF(detached_resource ->> 'modalAppId', '')
|
|
10687
|
+
ELSE NULLIF(detached_resource ->> 'daytonaOrganizationId', '') END)
|
|
10688
|
+
IS NOT DISTINCT FROM ${identity.routingDomain}
|
|
10689
|
+
AND (
|
|
10690
|
+
(detached_run.suspension_json ->> 'kind' = 'detached_runner'
|
|
10691
|
+
AND detached_run.suspension_json -> 'runnerAttempt' = to_jsonb(detached_attempt.attempt)
|
|
10692
|
+
AND detached_run.suspension_json ->> 'sandboxId' = detached_resource ->> 'sandboxId')
|
|
10693
|
+
OR (detached_run.suspension_json IS NULL
|
|
10694
|
+
AND detached_resource -> 'executionDetachedAt' IS NOT NULL
|
|
10695
|
+
AND detached_resource -> 'executionDetachedAt' <> 'null'::jsonb)
|
|
10696
|
+
)
|
|
10697
|
+
AND NOT EXISTS (SELECT 1 FROM ${tableName('attempts', options)} AS newer
|
|
10698
|
+
WHERE newer.run_id = detached_run.run_id
|
|
10699
|
+
AND newer.attempt > detached_attempt.attempt
|
|
10700
|
+
AND newer.status IN ('claimed', 'running', 'waiting', 'completed', 'failed'))
|
|
10701
|
+
AND NOT EXISTS (SELECT 1 FROM ${tableName('control', options)} AS cancel
|
|
10702
|
+
WHERE cancel.key = 'runtime_cancel:' || detached_run.run_id)
|
|
10703
|
+
)`;
|
|
10704
|
+
}
|
|
10705
|
+
|
|
10706
|
+
function protectedDetachedResourceSql(
|
|
10707
|
+
runId: string,
|
|
10708
|
+
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
10709
|
+
): string {
|
|
10710
|
+
return protectedDetachedSandboxSql(
|
|
10711
|
+
{
|
|
10712
|
+
runId,
|
|
10713
|
+
provider:
|
|
10714
|
+
"(CASE resource->>'kind' WHEN 'modal_sandbox' THEN 'modal' ELSE 'daytona' END)",
|
|
10715
|
+
sandboxId: "resource->>'sandboxId'",
|
|
10716
|
+
routingDomain:
|
|
10717
|
+
"(CASE resource->>'kind' WHEN 'modal_sandbox' THEN NULLIF(resource->>'modalAppId', '') ELSE NULLIF(resource->>'daytonaOrganizationId', '') END)",
|
|
10718
|
+
},
|
|
10719
|
+
options,
|
|
10720
|
+
);
|
|
10721
|
+
}
|
|
10722
|
+
|
|
10576
10723
|
export type PostgresSchedulerSandboxCleanupJob = {
|
|
10577
10724
|
provider: 'daytona' | 'modal';
|
|
10578
10725
|
sandboxId: string;
|
|
@@ -10636,6 +10783,7 @@ export async function enqueuePostgresSchedulerSandboxCleanupForAttempt(
|
|
|
10636
10783
|
) AS resource
|
|
10637
10784
|
WHERE resource->>'kind' IN ('daytona_sandbox', 'modal_sandbox')
|
|
10638
10785
|
AND NULLIF(resource->>'sandboxId', '') IS NOT NULL
|
|
10786
|
+
AND NOT ${protectedDetachedResourceSql('$1', options)}
|
|
10639
10787
|
ON CONFLICT (provider, sandbox_id, routing_domain_key) DO NOTHING
|
|
10640
10788
|
RETURNING sandbox_id
|
|
10641
10789
|
)
|
|
@@ -10646,7 +10794,8 @@ export async function enqueuePostgresSchedulerSandboxCleanupForAttempt(
|
|
|
10646
10794
|
return enqueued.rows.length;
|
|
10647
10795
|
}
|
|
10648
10796
|
|
|
10649
|
-
/** Queue
|
|
10797
|
+
/** Queue eligible current and retired resources; cancellation intent explicitly
|
|
10798
|
+
* admits the current runner before cancellation terminalizes. */
|
|
10650
10799
|
export async function enqueuePostgresSchedulerSandboxCleanupForRun(
|
|
10651
10800
|
client: PostgresSchedulerQueryClient,
|
|
10652
10801
|
input: { runId: string },
|
|
@@ -10686,6 +10835,7 @@ export async function enqueuePostgresSchedulerSandboxCleanupForRun(
|
|
|
10686
10835
|
AND attempt.resource_json IS NOT NULL
|
|
10687
10836
|
AND resource->>'kind' IN ('daytona_sandbox', 'modal_sandbox')
|
|
10688
10837
|
AND NULLIF(resource->>'sandboxId', '') IS NOT NULL
|
|
10838
|
+
AND NOT ${protectedDetachedResourceSql('$1', options)}
|
|
10689
10839
|
UNION ALL
|
|
10690
10840
|
SELECT operation.provider, operation.sandbox_id, operation.run_id,
|
|
10691
10841
|
operation.attempt, operation.environment, operation.routing_domain
|
|
@@ -10693,6 +10843,7 @@ export async function enqueuePostgresSchedulerSandboxCleanupForRun(
|
|
|
10693
10843
|
WHERE operation.run_id = $1
|
|
10694
10844
|
AND operation.state IN ('live', 'deleting')
|
|
10695
10845
|
AND operation.sandbox_id IS NOT NULL
|
|
10846
|
+
AND NOT ${protectedDetachedSandboxSql({ runId: 'operation.run_id', provider: 'operation.provider', sandboxId: 'operation.sandbox_id', routingDomain: 'operation.routing_domain' }, options)}
|
|
10696
10847
|
ON CONFLICT (provider, sandbox_id, routing_domain_key) DO NOTHING
|
|
10697
10848
|
`,
|
|
10698
10849
|
[input.runId],
|
|
@@ -10775,6 +10926,7 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
|
|
|
10775
10926
|
client: PostgresSchedulerQueryClient,
|
|
10776
10927
|
input: {
|
|
10777
10928
|
leaseOwner: string;
|
|
10929
|
+
runId?: string;
|
|
10778
10930
|
limit?: number;
|
|
10779
10931
|
leaseSeconds?: number;
|
|
10780
10932
|
environment?: string | null;
|
|
@@ -10868,6 +11020,8 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
|
|
|
10868
11020
|
AND (cleanup.lease_expires_at IS NULL OR cleanup.lease_expires_at <= now())
|
|
10869
11021
|
AND ($4::text IS NULL OR cleanup.environment = $4)
|
|
10870
11022
|
AND ($5::text[] IS NULL OR cleanup.provider = ANY($5::text[]))
|
|
11023
|
+
AND ($8::text IS NULL OR cleanup.run_id = $8)
|
|
11024
|
+
AND NOT ${protectedDetachedSandboxSql({ runId: 'cleanup.run_id', provider: 'cleanup.provider', sandboxId: 'cleanup.sandbox_id', routingDomain: 'cleanup.routing_domain' }, options)}
|
|
10871
11025
|
ORDER BY
|
|
10872
11026
|
CASE WHEN cleanup.diagnostic_json IS NOT NULL THEN 0 ELSE 1 END ASC,
|
|
10873
11027
|
cleanup.available_at ASC,
|
|
@@ -10933,7 +11087,7 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
|
|
|
10933
11087
|
attempt_count,
|
|
10934
11088
|
$1,
|
|
10935
11089
|
'claimed',
|
|
10936
|
-
jsonb_build_object('leaseSeconds', $3::integer)
|
|
11090
|
+
jsonb_build_object('leaseSeconds', $3::integer, 'runStatusAtClaim', terminal_status, 'authorization', 'terminal_cancel_or_retired_resource')
|
|
10937
11091
|
FROM claimed
|
|
10938
11092
|
RETURNING provider, sandbox_id, routing_domain
|
|
10939
11093
|
)
|
|
@@ -10952,6 +11106,7 @@ export async function claimPostgresSchedulerSandboxCleanupJobs(
|
|
|
10952
11106
|
providers,
|
|
10953
11107
|
RuntimeSandboxOperationState.Deleting,
|
|
10954
11108
|
RuntimeSandboxOperationState.Live,
|
|
11109
|
+
input.runId ?? null,
|
|
10955
11110
|
],
|
|
10956
11111
|
);
|
|
10957
11112
|
return claimed.rows.map((row) => ({
|
|
@@ -11599,7 +11754,11 @@ export type PostgresSchedulerCompletedRunnerTerminal = {
|
|
|
11599
11754
|
|
|
11600
11755
|
export async function listPostgresSchedulerCompletedRunnerTerminals(
|
|
11601
11756
|
client: PostgresSchedulerQueryClient,
|
|
11602
|
-
input: {
|
|
11757
|
+
input: {
|
|
11758
|
+
limit?: number;
|
|
11759
|
+
absurdReleaseId?: string | null;
|
|
11760
|
+
includeFailed?: boolean;
|
|
11761
|
+
} = {},
|
|
11603
11762
|
options?: Pick<PostgresSchedulerOptions, 'schema'>,
|
|
11604
11763
|
): Promise<PostgresSchedulerCompletedRunnerTerminal[]> {
|
|
11605
11764
|
const limit = Math.min(500, Math.max(1, Math.floor(input.limit ?? 100)));
|
|
@@ -11618,9 +11777,9 @@ export async function listPostgresSchedulerCompletedRunnerTerminals(
|
|
|
11618
11777
|
FROM ${tableName('attempts', options)} AS attempts
|
|
11619
11778
|
JOIN ${tableName('runs', options)} AS runs
|
|
11620
11779
|
ON runs.run_id = attempts.run_id
|
|
11621
|
-
WHERE attempts.status =
|
|
11780
|
+
WHERE attempts.status = ANY($4::text[])
|
|
11622
11781
|
AND attempts.lease_token IS NOT NULL
|
|
11623
|
-
AND attempts.runner_result_json ->> 'status' =
|
|
11782
|
+
AND attempts.runner_result_json ->> 'status' = ANY($3::text[])
|
|
11624
11783
|
AND runs.status IN ('queued', 'running', 'waiting')
|
|
11625
11784
|
AND (
|
|
11626
11785
|
$1::text IS NULL
|
|
@@ -11629,7 +11788,12 @@ export async function listPostgresSchedulerCompletedRunnerTerminals(
|
|
|
11629
11788
|
ORDER BY attempts.updated_at ASC, attempts.run_id ASC
|
|
11630
11789
|
LIMIT $2
|
|
11631
11790
|
`,
|
|
11632
|
-
[
|
|
11791
|
+
[
|
|
11792
|
+
input.absurdReleaseId?.trim() || null,
|
|
11793
|
+
limit,
|
|
11794
|
+
input.includeFailed ? ['completed', 'failed'] : ['completed'],
|
|
11795
|
+
input.includeFailed ? ['running', 'waiting'] : ['running'],
|
|
11796
|
+
],
|
|
11633
11797
|
);
|
|
11634
11798
|
return terminals.rows.map((row) => ({
|
|
11635
11799
|
runId: row.run_id,
|
|
@@ -11727,19 +11891,10 @@ export async function heartbeatPostgresSchedulerDetachedRunner(
|
|
|
11727
11891
|
): Promise<
|
|
11728
11892
|
'queued' | 'running' | 'waiting' | 'completed' | 'failed' | 'cancelled' | null
|
|
11729
11893
|
> {
|
|
11730
|
-
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
updated_at = now()
|
|
11735
|
-
WHERE run_id = $1
|
|
11736
|
-
AND attempt = $2
|
|
11737
|
-
AND status IN ('claimed', 'running', 'waiting')
|
|
11738
|
-
RETURNING run_id
|
|
11739
|
-
`,
|
|
11740
|
-
[input.runId, input.attempt],
|
|
11741
|
-
);
|
|
11742
|
-
const run = await client.query<{
|
|
11894
|
+
// Return the status from the same statement that renews this exact attempt.
|
|
11895
|
+
// A separate run read can observe a replacement's waiting state after this
|
|
11896
|
+
// attempt was retired, incorrectly allowing the old runner to execute.
|
|
11897
|
+
const heartbeat = await client.query<{
|
|
11743
11898
|
status:
|
|
11744
11899
|
| 'queued'
|
|
11745
11900
|
| 'running'
|
|
@@ -11749,17 +11904,35 @@ export async function heartbeatPostgresSchedulerDetachedRunner(
|
|
|
11749
11904
|
| 'cancelled';
|
|
11750
11905
|
}>(
|
|
11751
11906
|
`
|
|
11907
|
+
WITH heartbeat AS (
|
|
11908
|
+
UPDATE ${tableName('attempts', options)} AS target
|
|
11909
|
+
SET heartbeat_at = now(),
|
|
11910
|
+
updated_at = now()
|
|
11911
|
+
FROM ${tableName('runs', options)} AS run
|
|
11912
|
+
WHERE target.run_id = $1
|
|
11913
|
+
AND target.attempt = $2
|
|
11914
|
+
AND target.status IN ('claimed', 'running', 'waiting')
|
|
11915
|
+
AND run.run_id = target.run_id
|
|
11916
|
+
AND run.status IN ('queued', 'running', 'waiting')
|
|
11917
|
+
AND NOT EXISTS (
|
|
11918
|
+
SELECT 1
|
|
11919
|
+
FROM ${tableName('attempts', options)} AS newer
|
|
11920
|
+
WHERE newer.run_id = target.run_id
|
|
11921
|
+
AND newer.attempt > target.attempt
|
|
11922
|
+
)
|
|
11923
|
+
RETURNING run.status
|
|
11924
|
+
)
|
|
11925
|
+
SELECT status FROM heartbeat
|
|
11926
|
+
UNION ALL
|
|
11752
11927
|
SELECT status
|
|
11753
11928
|
FROM ${tableName('runs', options)}
|
|
11754
11929
|
WHERE run_id = $1
|
|
11930
|
+
AND status IN ('completed', 'failed', 'cancelled')
|
|
11931
|
+
AND NOT EXISTS (SELECT 1 FROM heartbeat)
|
|
11755
11932
|
`,
|
|
11756
|
-
[input.runId],
|
|
11933
|
+
[input.runId, input.attempt],
|
|
11757
11934
|
);
|
|
11758
|
-
|
|
11759
|
-
if (status === 'completed' || status === 'failed' || status === 'cancelled') {
|
|
11760
|
-
return status;
|
|
11761
|
-
}
|
|
11762
|
-
return heartbeat.rows.length > 0 ? status : null;
|
|
11935
|
+
return heartbeat.rows[0]?.status ?? null;
|
|
11763
11936
|
}
|
|
11764
11937
|
|
|
11765
11938
|
export async function claimPostgresSchedulerSignal(
|