feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,307 @@
// PostgreSQL source for remote-execution dispatch candidates and lease recovery.
import type {
ClusterDispatchCandidate,
ClusterDispatchCandidatePage,
ClusterDispatchCandidateCursor,
ClusterDispatchRecovery,
ClusterDispatchSource,
} from '@qinglong/runtime-core/remote-dispatch';
import {
assertRemoteDispatchPageSize,
normalizeClusterDispatchCandidate,
normalizeClusterDispatchCursor,
} from '@qinglong/runtime-core/remote-dispatch';
import type {
PostgresPool,
RunDispatchLeaseRecord,
RunDispatchLeaseStatus,
} from '@qinglong/runtime-core';
import {
RUN_DISPATCH_LEASE_STATUSES,
assertRunDispatchId,
assertRunDispatchLeaseRecord,
} from '@qinglong/runtime-core';
type Row = Record<string, unknown>;
const CANDIDATE_COLUMNS = `
run.id AS "runId",
attempt.id AS "attemptId",
COALESCE(workflow_task.project_id, run.project_id) AS "projectId",
COALESCE(workflow_task.task_id, run.task_id) AS "taskId",
COALESCE(workflow_task.task_revision, run.task_revision) AS "taskRevision",
run.priority,
COALESCE(workflow_task.admitted_at_ms, run.queued_at_ms) AS "queuedAtMs",
attempt.created_at_ms AS "attemptCreatedAtMs",
attempt.attempt AS "attemptNumber",
attempt.executor_type AS "executorType"`.trim();
const LEASE_COLUMNS = `
lease.status AS "leaseStatus",
lease.version AS "leaseVersion",
lease.lease_generation AS "leaseGeneration",
lease.worker_id AS "workerId",
lease.worker_session_id AS "workerSessionId",
lease.worker_generation AS "workerGeneration",
lease.lease_token_digest AS "leaseTokenDigest",
lease.acquired_at_ms AS "acquiredAtMs",
lease.renewed_at_ms AS "renewedAtMs",
lease.expires_at_ms AS "expiresAtMs",
lease.released_at_ms AS "releasedAtMs",
lease.release_reason AS "releaseReason",
lease.completed_at_ms AS "completedAtMs",
lease.updated_at_ms AS "leaseUpdatedAtMs"`.trim();
function string(row: Row, key: string): string {
const value = row[key];
if (typeof value !== 'string' || value.length === 0) {
throw new TypeError(`PostgreSQL cluster dispatch ${key} is invalid`);
}
return value;
}
function integer(row: Row, key: string): number {
const value = row[key];
const normalized = typeof value === 'string' && /^(0|[1-9]\d*)$/.test(value)
? Number(value)
: value;
if (typeof normalized !== 'number' || !Number.isSafeInteger(normalized)) {
throw new TypeError(`PostgreSQL cluster dispatch ${key} is invalid`);
}
return normalized;
}
function optionalInteger(row: Row, key: string): number | undefined {
return row[key] === null || row[key] === undefined ? undefined : integer(row, key);
}
function optionalString(row: Row, key: string): string | undefined {
return row[key] === null || row[key] === undefined ? undefined : string(row, key);
}
function candidate(row: Row): ClusterDispatchCandidate {
return normalizeClusterDispatchCandidate({
runId: string(row, 'runId'),
attemptId: string(row, 'attemptId'),
projectId: string(row, 'projectId'),
taskId: string(row, 'taskId'),
taskRevision: string(row, 'taskRevision'),
priority: integer(row, 'priority'),
queuedAtMs: integer(row, 'queuedAtMs'),
attemptCreatedAtMs: integer(row, 'attemptCreatedAtMs'),
attemptNumber: integer(row, 'attemptNumber'),
executorType: string(row, 'executorType') as ClusterDispatchCandidate['executorType'],
});
}
function lease(row: Row): RunDispatchLeaseRecord {
const status = string(row, 'leaseStatus') as RunDispatchLeaseStatus;
if (!RUN_DISPATCH_LEASE_STATUSES.includes(status)) {
throw new TypeError('PostgreSQL cluster dispatch lease status is invalid');
}
const releasedAtMs = optionalInteger(row, 'releasedAtMs');
const releaseReason = optionalString(row, 'releaseReason');
const completedAtMs = optionalInteger(row, 'completedAtMs');
const value: RunDispatchLeaseRecord = Object.freeze({
attemptId: string(row, 'attemptId'),
runId: string(row, 'runId'),
status,
version: integer(row, 'leaseVersion'),
leaseGeneration: integer(row, 'leaseGeneration'),
workerId: string(row, 'workerId'),
workerSessionId: string(row, 'workerSessionId'),
workerGeneration: integer(row, 'workerGeneration'),
leaseTokenDigest: string(row, 'leaseTokenDigest'),
acquiredAtMs: integer(row, 'acquiredAtMs'),
renewedAtMs: integer(row, 'renewedAtMs'),
expiresAtMs: integer(row, 'expiresAtMs'),
updatedAtMs: integer(row, 'leaseUpdatedAtMs'),
...(releasedAtMs === undefined ? {} : { releasedAtMs }),
...(releaseReason === undefined ? {} : {
releaseReason: releaseReason as NonNullable<RunDispatchLeaseRecord['releaseReason']>,
}),
...(completedAtMs === undefined ? {} : { completedAtMs }),
});
assertRunDispatchLeaseRecord(value);
return value;
}
function cursor(value: ClusterDispatchCandidate): ClusterDispatchCandidateCursor {
return Object.freeze({
priority: value.priority,
queuedAtMs: value.queuedAtMs,
attemptCreatedAtMs: value.attemptCreatedAtMs,
attemptId: value.attemptId,
});
}
export class PostgresClusterDispatchSource implements ClusterDispatchSource {
constructor(private readonly pool: PostgresPool) {
if (!pool || typeof pool.query !== 'function') {
throw new TypeError('PostgreSQL cluster dispatch pool is invalid');
}
}
async listClusterDispatchCandidates(options: Readonly<{
limit: number;
after?: ClusterDispatchCandidateCursor;
}>): Promise<ClusterDispatchCandidatePage> {
if (!options || typeof options !== 'object' || Array.isArray(options)) {
throw new TypeError('PostgreSQL cluster dispatch options are invalid');
}
const keys = Object.keys(options);
if (!keys.includes('limit') || keys.some((key) => !['after', 'limit'].includes(key))) {
throw new TypeError('PostgreSQL cluster dispatch options shape is invalid');
}
assertRemoteDispatchPageSize(options.limit);
const after = options.after === undefined
? undefined
: normalizeClusterDispatchCursor(options.after);
const result = await this.pool.query<Row>(
`WITH observation AS MATERIALIZED (
SELECT floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint
AS observed_at_ms
), candidates AS MATERIALIZED (
SELECT ${CANDIDATE_COLUMNS}
FROM observation
JOIN "ql3"."runs" AS run ON true
JOIN "ql3"."run_attempts" AS attempt ON attempt.run_id = run.id
LEFT JOIN
"ql3"."plugin_package_workflow_task_attempt_admissions"
AS workflow_task
ON workflow_task.attempt_id = attempt.id
LEFT JOIN "ql3"."step_runs" AS workflow_step
ON workflow_step.run_id = workflow_task.run_id
AND workflow_step.id = workflow_task.step_run_id
LEFT JOIN "ql3"."run_dispatch_leases" AS lease
ON lease.attempt_id = attempt.id
WHERE run.execution_owner = 'runtime'
AND run.cancel_requested_at_ms IS NULL
AND attempt.status = 'claimed'
AND attempt.executor_type = 'remote_worker'
AND (
(
workflow_task.attempt_id IS NULL
AND run.status IN ('queued', 'dispatching')
AND run.queued_at_ms IS NOT NULL
) OR (
workflow_task.attempt_id IS NOT NULL
AND run.status = 'running'
AND attempt.step_run_id = workflow_task.step_run_id
AND workflow_step.status = 'ready'
AND workflow_step.version = workflow_task.step_run_version
AND workflow_step.step_run_digest =
workflow_task.step_run_digest
)
)
AND NOT EXISTS (
SELECT 1 FROM "ql3"."run_attempts" AS newer
WHERE newer.run_id = run.id
AND newer.attempt > attempt.attempt
AND (
workflow_task.attempt_id IS NULL
OR newer.step_run_id = attempt.step_run_id
)
)
AND (
lease.attempt_id IS NULL OR lease.status = 'released'
OR (lease.status = 'leased' AND lease.expires_at_ms <= observation.observed_at_ms)
)
AND (
$1::integer IS NULL OR run.priority < $1
OR (
run.priority = $1 AND
COALESCE(workflow_task.admitted_at_ms, run.queued_at_ms) > $2
)
OR (run.priority = $1
AND COALESCE(
workflow_task.admitted_at_ms, run.queued_at_ms
) = $2
AND attempt.created_at_ms > $3)
OR (run.priority = $1
AND COALESCE(
workflow_task.admitted_at_ms, run.queued_at_ms
) = $2
AND attempt.created_at_ms = $3 AND attempt.id > $4)
)
ORDER BY run.priority DESC,
COALESCE(
workflow_task.admitted_at_ms, run.queued_at_ms
),
attempt.created_at_ms, attempt.id
LIMIT $5
)
SELECT observation.observed_at_ms AS "observedAtMs", candidates.*
FROM observation LEFT JOIN candidates ON true
ORDER BY candidates.priority DESC, candidates."queuedAtMs",
candidates."attemptCreatedAtMs", candidates."attemptId"`,
[
after?.priority ?? null,
after?.queuedAtMs ?? null,
after?.attemptCreatedAtMs ?? null,
after?.attemptId ?? null,
options.limit + 1,
],
);
if (result.rows.length < 1) {
throw new TypeError('PostgreSQL cluster dispatch observation is missing');
}
const observedAtMs = integer(result.rows[0]!, 'observedAtMs');
const mapped = result.rows
.filter((row) => row.attemptId !== null && row.attemptId !== undefined)
.map(candidate);
const truncated = mapped.length > options.limit;
const candidates = Object.freeze(mapped.slice(0, options.limit));
const last = candidates.at(-1);
return Object.freeze({
observedAtMs,
candidates,
truncated,
...(truncated && last ? { next: cursor(last) } : {}),
});
}
async findClusterDispatchRecovery(offerId: string): Promise<ClusterDispatchRecovery | null> {
assertRunDispatchId('offerId', offerId);
const result = await this.pool.query<Row>(
`WITH observation AS MATERIALIZED (
SELECT floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint
AS observed_at_ms
)
SELECT observation.observed_at_ms AS "observedAtMs",
${CANDIDATE_COLUMNS}, ${LEASE_COLUMNS},
(
worker.worker_id = lease.worker_id
AND worker.session_id = lease.worker_session_id
AND worker.generation = lease.worker_generation
AND worker.status IN ('online', 'draining')
AND worker.lease_expires_at_ms > observation.observed_at_ms
) AS "workerCurrent"
FROM observation
JOIN "ql3"."run_dispatch_leases" AS lease ON lease.offer_id = $1
JOIN "ql3"."runs" AS run ON run.id = lease.run_id
JOIN "ql3"."run_attempts" AS attempt ON attempt.id = lease.attempt_id
LEFT JOIN
"ql3"."plugin_package_workflow_task_attempt_admissions"
AS workflow_task
ON workflow_task.attempt_id = attempt.id
LEFT JOIN "ql3"."step_runs" AS workflow_step
ON workflow_step.run_id = workflow_task.run_id
AND workflow_step.id = workflow_task.step_run_id
LEFT JOIN "ql3"."worker_sessions" AS worker
ON worker.worker_id = lease.worker_id
LIMIT 2`,
[offerId],
);
if (result.rows.length === 0) return null;
if (result.rows.length !== 1 || typeof result.rows[0]!.workerCurrent !== 'boolean') {
throw new TypeError('PostgreSQL cluster dispatch recovery is invalid');
}
return Object.freeze({
observedAtMs: integer(result.rows[0]!, 'observedAtMs'),
candidate: candidate(result.rows[0]!),
lease: lease(result.rows[0]!),
workerCurrent: result.rows[0]!.workerCurrent as boolean,
});
}
}
@@ -0,0 +1,96 @@
// PostgreSQL Remote Worker recovery evidence is owned by this domain.
import type {
ClusterControlRecoveryEvidence,
ClusterControlRecoveryEvidenceInspectionContext,
ClusterControlRecoveryExecutorEvidenceProvider,
ClusterControlRecoveryProbeTarget,
} from '@qinglong/runtime-core';
import type { PostgresPool } from '@qinglong/runtime-core';
import type { WorkerExecutionAttestationRepository } from '@qinglong/runtime-core/worker-attestation';
export const REMOTE_WORKER_ATTESTATION_LIMITS = Object.freeze({
defaultRunningFreshnessMs: 30_000,
maxRunningFreshnessMs: 300_000,
});
type Row = Record<string, unknown>;
export class PostgresRemoteWorkerAttestationEvidenceProvider
implements ClusterControlRecoveryExecutorEvidenceProvider
{
readonly executorType = 'remote-worker';
readonly requiredIdentity = Object.freeze([
'workerId',
'workerSessionId',
'workerGeneration',
'leaseTokenDigest',
'leaseGeneration',
'leaseVersion',
'offerId',
'executorHandle',
] as const);
private readonly runningFreshnessMs: number;
constructor(
private readonly pool: PostgresPool,
private readonly attestations: WorkerExecutionAttestationRepository,
options: Readonly<{ runningFreshnessMs?: number }> = {},
) {
const freshness =
options.runningFreshnessMs ??
REMOTE_WORKER_ATTESTATION_LIMITS.defaultRunningFreshnessMs;
if (
!Number.isSafeInteger(freshness) ||
freshness < 1_000 ||
freshness > REMOTE_WORKER_ATTESTATION_LIMITS.maxRunningFreshnessMs
) {
throw new RangeError('Remote Worker attestation freshness is invalid');
}
this.runningFreshnessMs = freshness;
}
async inspect(
target: ClusterControlRecoveryProbeTarget,
context: ClusterControlRecoveryEvidenceInspectionContext,
): Promise<ClusterControlRecoveryEvidence> {
if (context.signal.aborted) {
return Object.freeze({ status: 'unknown', reason: 'provider_unavailable' });
}
const attestation = await this.attestations.findLatestExact({
runId: target.runId,
attemptId: target.attemptId,
workerId: target.workerId!,
workerSessionId: target.workerSessionId!,
workerGeneration: target.workerGeneration!,
leaseTokenDigest: target.leaseTokenDigest!,
leaseGeneration: target.leaseGeneration!,
leaseVersion: target.leaseVersion!,
offerId: target.offerId!,
callbackSequence: target.callbackSequence,
executorHandle: target.executorHandle!,
});
if (!attestation) {
return Object.freeze({ status: 'unknown', reason: 'provider_unavailable' });
}
if (attestation.state === 'stopped') {
return Object.freeze({ status: 'not_running' });
}
const observed = await this.pool.query<Row>(
`SELECT floor(extract(epoch FROM statement_timestamp()) * 1000)::bigint AS "observedAtMs"`,
);
const raw = observed.rows[0]?.observedAtMs;
const observedAtMs =
typeof raw === 'string' && /^\d+$/.test(raw) ? Number(raw) : raw;
if (
observed.rows.length !== 1 ||
typeof observedAtMs !== 'number' ||
!Number.isSafeInteger(observedAtMs) ||
observedAtMs < attestation.receivedAtMs ||
observedAtMs - attestation.receivedAtMs > this.runningFreshnessMs
) {
return Object.freeze({ status: 'unknown', reason: 'provider_unavailable' });
}
return Object.freeze({ status: 'running' });
}
}
@@ -0,0 +1,584 @@
// PostgreSQL Remote Worker lease control is owned by this domain.
import type { PostgresClient, PostgresPool } from '@qinglong/runtime-core';
import { digestRunDispatchLeaseToken } from '@qinglong/runtime-core';
import {
InvalidRemoteWorkerLeaseControlError,
RemoteWorkerLeaseControlFenceRejectedError,
RemoteWorkerLeaseControlUnavailableError,
assertRemoteWorkerLeaseControlDuration,
normalizeRemoteWorkerLeaseControlCommand,
normalizeRemoteWorkerLeaseControlResult,
type RemoteWorkerLeaseControlCommand,
type RemoteWorkerLeaseControlRepository,
type RemoteWorkerLeaseControlResult,
type RemoteWorkerStopReason,
type RemoteWorkerTerminalStatus,
} from '@qinglong/runtime-core/remote-worker-lease-control';
import {
normalizeStepRunRecord,
type StepRunRecord,
} from '@qinglong/runtime-core/step-run';
import { lockAttemptAuthority } from '../run/attemptAuthorityLock';
type Row = Record<string, unknown>;
type MutationCommand = RemoteWorkerLeaseControlCommand & Readonly<{
leaseDurationMs: number;
timeoutEventId: string;
}>;
const TERMINAL = new Set<RemoteWorkerTerminalStatus>([
'succeeded', 'failed', 'cancelled', 'timed_out', 'lost',
]);
const STOP_REASONS = new Set<RemoteWorkerStopReason>([
'user', 'policy', 'shutdown', 'reconcile', 'timeout',
]);
function text(row: Row, key: string): string {
const value = row[key];
if (typeof value !== 'string' || value.length < 1) {
throw new TypeError(`PostgreSQL Worker lease control ${key} is invalid`);
}
return value;
}
function integer(row: Row, key: string): number {
const raw = row[key];
const value = typeof raw === 'string' && /^(0|[1-9]\d*)$/.test(raw)
? Number(raw)
: raw;
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
throw new TypeError(`PostgreSQL Worker lease control ${key} is invalid`);
}
return value;
}
function optionalInteger(row: Row, key: string): number | undefined {
return row[key] === null || row[key] === undefined
? undefined
: integer(row, key);
}
function optionalText(row: Row, key: string): string | undefined {
return row[key] === null || row[key] === undefined
? undefined
: text(row, key);
}
function isWorkflowTaskAttempt(aggregate: Row): boolean {
return (
aggregate.workflowAttemptId !== null &&
aggregate.workflowAttemptId !== undefined
);
}
function workflowStepRun(aggregate: Row): Readonly<StepRunRecord> {
try {
const value = normalizeStepRunRecord(
aggregate.workflowStepJson as StepRunRecord,
);
if (
value.runId !== aggregate.runId ||
value.id !== aggregate.workflowStepRunId ||
value.id !== aggregate.attemptStepRunId ||
value.version !== integer(aggregate, 'workflowStepVersion') ||
value.stepRunDigest !== aggregate.workflowStepDigest
) {
throw new TypeError();
}
return value;
} catch {
throw new TypeError(
'PostgreSQL Worker lease control Workflow StepRun is invalid',
);
}
}
function workflowStepAtAdmissionEpoch(aggregate: Row): boolean {
const stepRun = workflowStepRun(aggregate);
return (
stepRun.version === integer(aggregate, 'admittedWorkflowStepVersion') &&
stepRun.stepRunDigest === aggregate.admittedWorkflowStepDigest
);
}
function reject(
command: Pick<RemoteWorkerLeaseControlCommand, 'attemptId'>,
reason: ConstructorParameters<
typeof RemoteWorkerLeaseControlFenceRejectedError
>[1],
): never {
throw new RemoteWorkerLeaseControlFenceRejectedError(
command.attemptId,
reason,
);
}
function normalizeMutationCommand(value: MutationCommand): MutationCommand {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new InvalidRemoteWorkerLeaseControlError(
'lease control mutation is invalid',
);
}
const { leaseDurationMs, timeoutEventId, ...wire } = value;
const command = normalizeRemoteWorkerLeaseControlCommand(wire);
assertRemoteWorkerLeaseControlDuration(leaseDurationMs);
if (
typeof timeoutEventId !== 'string' || timeoutEventId.length < 1 ||
timeoutEventId.length > 36 || /[\u0000-\u001f\u007f]/.test(timeoutEventId)
) {
throw new InvalidRemoteWorkerLeaseControlError(
'timeout event identity is invalid',
);
}
return Object.freeze({ ...command, leaseDurationMs, timeoutEventId });
}
async function begin(client: PostgresClient): Promise<void> {
await client.query('BEGIN');
await client.query("SET LOCAL statement_timeout = '5s'");
await client.query("SET LOCAL lock_timeout = '1s'");
await client.query("SET LOCAL idle_in_transaction_session_timeout = '10s'");
}
async function databaseNow(client: PostgresClient): Promise<number> {
const result = await client.query<Row>(`
SELECT floor(extract(epoch FROM statement_timestamp()) * 1000)::bigint AS "nowMs"
`);
if (result.rows.length !== 1) {
throw new TypeError('PostgreSQL Worker lease control clock is invalid');
}
return integer(result.rows[0]!, 'nowMs');
}
function common(
command: RemoteWorkerLeaseControlCommand,
): Pick<
RemoteWorkerLeaseControlResult,
'projectId' | 'runId' | 'attemptId' | 'offerId' | 'leaseGeneration'
> {
return {
projectId: command.projectId,
runId: command.runId,
attemptId: command.attemptId,
offerId: command.offerId,
leaseGeneration: command.leaseGeneration,
};
}
function assertIdentity(
command: RemoteWorkerLeaseControlCommand,
worker: Row | undefined,
aggregate: Row | undefined,
lease: Row | undefined,
observedAtMs: number,
): asserts aggregate is Row {
if (!aggregate || !lease) reject(command, 'missing');
if (!worker) reject(command, 'worker_unavailable');
if (worker.workerId !== command.workerId) reject(command, 'worker_mismatch');
if (worker.sessionId !== command.workerSessionId) {
reject(command, 'worker_session_mismatch');
}
if (integer(worker, 'workerGeneration') !== command.workerGeneration) {
reject(command, 'worker_generation_mismatch');
}
if (
!['online', 'draining'].includes(String(worker.workerStatus)) ||
integer(worker, 'workerLeaseExpiresAtMs') <= observedAtMs
) reject(command, 'worker_unavailable');
const digest = digestRunDispatchLeaseToken(command.leaseToken);
if (
aggregate.runId !== command.runId ||
aggregate.attemptRunId !== command.runId ||
lease.runId !== command.runId
) reject(command, 'run_mismatch');
if (aggregate.projectId !== command.projectId) {
reject(command, 'project_mismatch');
}
if (aggregate.executionOwner !== 'runtime') {
reject(command, 'execution_owner_mismatch');
}
if (aggregate.executorType !== 'remote_worker') {
reject(command, 'executor_mismatch');
}
if (
lease.workerId !== command.workerId ||
aggregate.attemptWorkerId !== command.workerId
) reject(command, 'worker_mismatch');
if (
lease.workerSessionId !== command.workerSessionId ||
aggregate.attemptWorkerSessionId !== command.workerSessionId
) reject(command, 'worker_session_mismatch');
if (
integer(lease, 'workerGeneration') !== command.workerGeneration ||
integer(aggregate, 'attemptWorkerGeneration') !== command.workerGeneration
) reject(command, 'worker_generation_mismatch');
if (
integer(lease, 'leaseGeneration') !== command.leaseGeneration ||
integer(aggregate, 'attemptLeaseGeneration') !== command.leaseGeneration
) reject(command, 'lease_generation_mismatch');
if (
lease.leaseTokenDigest !== digest ||
aggregate.attemptLeaseTokenDigest !== digest
) reject(command, 'lease_token_mismatch');
if (
lease.offerId !== command.offerId ||
aggregate.attemptOfferId !== command.offerId
) reject(command, 'offer_mismatch');
if (isWorkflowTaskAttempt(aggregate)) {
workflowStepRun(aggregate);
} else if (
aggregate.attemptStepRunId !== null &&
aggregate.attemptStepRunId !== undefined
) {
reject(command, 'run_mismatch');
}
}
export class PostgresRemoteWorkerLeaseControlRepository
implements RemoteWorkerLeaseControlRepository {
constructor(private readonly pool: PostgresPool) {
if (!pool || typeof pool.connect !== 'function') {
throw new TypeError('PostgreSQL Worker lease control pool is invalid');
}
}
async control(
value: MutationCommand,
): Promise<Readonly<RemoteWorkerLeaseControlResult>> {
const command = normalizeMutationCommand(value);
return this.transaction(async (client) => {
await lockAttemptAuthority(client, command.attemptId);
const worker = await client.query<Row>(`
SELECT worker_id AS "workerId", session_id AS "sessionId",
generation AS "workerGeneration", status AS "workerStatus",
lease_expires_at_ms AS "workerLeaseExpiresAtMs"
FROM "ql3"."worker_sessions" WHERE worker_id = $1 FOR UPDATE
`, [command.workerId]);
const aggregate = await client.query<Row>(`
SELECT run.id AS "runId",
COALESCE(workflow_task.project_id, run.project_id)
AS "projectId",
run.status AS "runStatus", run.execution_owner AS "executionOwner",
run.cancel_requested_at_ms AS "cancelRequestedAtMs",
run.cancel_reason AS "cancelReason", run.version AS "runVersion",
run.event_sequence AS "eventSequence",
attempt.id AS "attemptId", attempt.run_id AS "attemptRunId",
attempt.step_run_id AS "attemptStepRunId",
attempt.status AS "attemptStatus",
attempt.executor_type AS "executorType",
attempt.worker_id AS "attemptWorkerId",
attempt.worker_session_id AS "attemptWorkerSessionId",
attempt.worker_generation AS "attemptWorkerGeneration",
attempt.lease_generation AS "attemptLeaseGeneration",
attempt.lease_version AS "attemptLeaseVersion",
attempt.lease_token_digest AS "attemptLeaseTokenDigest",
attempt.offer_id AS "attemptOfferId",
attempt.deadline_at_ms AS "deadlineAtMs",
workflow_task.attempt_id AS "workflowAttemptId",
workflow_task.step_run_id AS "workflowStepRunId",
workflow_task.step_run_version AS
"admittedWorkflowStepVersion",
workflow_task.step_run_digest AS
"admittedWorkflowStepDigest"
FROM "ql3"."runs" AS run
INNER JOIN "ql3"."run_attempts" AS attempt ON attempt.id = $2
LEFT JOIN
"ql3"."plugin_package_workflow_task_attempt_admissions"
AS workflow_task
ON workflow_task.attempt_id = attempt.id
WHERE run.id = $1 FOR UPDATE OF run, attempt
`, [command.runId, command.attemptId]);
const aggregateRow = aggregate.rows[0];
let lockedAggregate = aggregateRow;
if (aggregateRow && isWorkflowTaskAttempt(aggregateRow)) {
const step = await client.query<Row>(
`SELECT version AS "workflowStepVersion",
step_run_digest AS "workflowStepDigest",
step_run_json AS "workflowStepJson"
FROM "ql3"."step_runs"
WHERE run_id = $1 AND id = $2
FOR UPDATE`,
[command.runId, aggregateRow.workflowStepRunId],
);
lockedAggregate = Object.freeze({
...aggregateRow,
...(step.rows[0] ?? {}),
});
}
const lease = await client.query<Row>(`
SELECT run_id AS "runId", status AS "leaseStatus",
version AS "leaseVersion", lease_generation AS "leaseGeneration",
worker_id AS "workerId", worker_session_id AS "workerSessionId",
worker_generation AS "workerGeneration",
lease_token_digest AS "leaseTokenDigest", offer_id AS "offerId",
expires_at_ms AS "leaseExpiresAtMs"
FROM "ql3"."run_dispatch_leases"
WHERE attempt_id = $1 FOR UPDATE
`, [command.attemptId]);
const observedAtMs = await databaseNow(client);
assertIdentity(
command,
worker.rows[0],
lockedAggregate,
lease.rows[0],
observedAtMs,
);
const state = lockedAggregate!;
const currentLease = lease.rows[0]!;
const runStatus = String(state.runStatus);
const attemptStatus = String(state.attemptStatus);
const workflowTask = isWorkflowTaskAttempt(state);
const stepStatus = workflowTask
? workflowStepRun(state).status
: undefined;
const attemptTerminal = TERMINAL.has(
attemptStatus as RemoteWorkerTerminalStatus,
);
const scopeTerminal = workflowTask
? TERMINAL.has(stepStatus as RemoteWorkerTerminalStatus)
: TERMINAL.has(runStatus as RemoteWorkerTerminalStatus);
if (
scopeTerminal ||
attemptTerminal
) {
if (
(workflowTask ? stepStatus !== attemptStatus : runStatus !== attemptStatus) ||
!scopeTerminal ||
!attemptTerminal ||
currentLease.leaseStatus !== 'completed'
) reject(command, 'state_mismatch');
return normalizeRemoteWorkerLeaseControlResult({
status: 'terminal',
...common(command),
terminalStatus: attemptStatus as RemoteWorkerTerminalStatus,
});
}
if (
currentLease.leaseStatus !== 'leased' ||
integer(currentLease, 'leaseVersion') !== command.expectedLeaseVersion ||
integer(state, 'attemptLeaseVersion') !== command.expectedLeaseVersion
) reject(command, 'version_mismatch');
if (integer(currentLease, 'leaseExpiresAtMs') <= observedAtMs) {
reject(command, 'lease_expired');
}
if (
!['claimed', 'starting', 'running'].includes(attemptStatus) ||
(workflowTask
? runStatus !== 'running' ||
(attemptStatus === 'running'
? stepStatus !== 'running'
: stepStatus !== 'ready' ||
!workflowStepAtAdmissionEpoch(state))
: !['dispatching', 'running'].includes(runStatus) ||
(attemptStatus === 'running') !== (runStatus === 'running'))
) reject(command, 'state_mismatch');
let cancelRequestedAtMs = optionalInteger(state, 'cancelRequestedAtMs');
let cancelReason = optionalText(state, 'cancelReason');
let workflowTimeoutRequestedAtMs: number | undefined;
const deadlineAtMs = optionalInteger(state, 'deadlineAtMs');
if (
cancelRequestedAtMs === undefined &&
deadlineAtMs !== undefined &&
deadlineAtMs <= observedAtMs
) {
const runVersion = integer(state, 'runVersion');
const eventSequence = integer(state, 'eventSequence') + 1;
if (runVersion >= 2_147_483_647 || eventSequence > 2_147_483_647) {
throw new RangeError('Worker lease control Run counter overflowed');
}
const timeoutDedupeKey =
`remote-timeout:${command.attemptId}:${command.leaseGeneration}`;
if (workflowTask) {
const existing = await client.query<Row>(
`SELECT created_at_ms AS "createdAtMs"
FROM "ql3"."run_events"
WHERE run_id = $1 AND dedupe_key = $2`,
[command.runId, timeoutDedupeKey],
);
if (existing.rows.length > 1) {
throw new TypeError(
'PostgreSQL Worker Workflow timeout event is invalid',
);
}
if (existing.rows.length === 1) {
workflowTimeoutRequestedAtMs = integer(
existing.rows[0]!,
'createdAtMs',
);
} else {
const updated = await client.query(`
UPDATE "ql3"."runs"
SET version = $2, event_sequence = $3
WHERE id = $1 AND version = $4
AND cancel_requested_at_ms IS NULL
AND status = 'running'
`, [
command.runId,
runVersion + 1,
eventSequence,
runVersion,
]);
if (updated.rowCount !== 1) reject(command, 'version_mismatch');
await client.query(`
INSERT INTO "ql3"."run_events" (
id, run_id, sequence, type, dedupe_key, actor_type, actor_id,
attempt_id, step_run_id, payload, created_at_ms
) VALUES (
$1, $2, $3, 'workflow.task_timeout_requested', $4, 'system',
'runtime:timeout', $5, $6, $7::jsonb, $8
)
`, [
command.timeoutEventId,
command.runId,
eventSequence,
timeoutDedupeKey,
command.attemptId,
text(state, 'workflowStepRunId'),
JSON.stringify({
attempt_id: command.attemptId,
step_run_id: text(state, 'workflowStepRunId'),
lease_generation: command.leaseGeneration,
execution_scope: 'workflow_task',
reason: 'timeout',
deadline_at_ms: deadlineAtMs,
}),
observedAtMs,
]);
workflowTimeoutRequestedAtMs = observedAtMs;
}
} else {
const updated = await client.query(`
UPDATE "ql3"."runs"
SET cancel_requested_at_ms = $2, cancel_reason = 'timeout',
version = $3, event_sequence = $4
WHERE id = $1 AND version = $5 AND cancel_requested_at_ms IS NULL
AND status IN ('dispatching', 'running')
`, [
command.runId,
observedAtMs,
runVersion + 1,
eventSequence,
runVersion,
]);
if (updated.rowCount !== 1) reject(command, 'version_mismatch');
await client.query(`
INSERT INTO "ql3"."run_events" (
id, run_id, sequence, type, dedupe_key, actor_type, actor_id,
attempt_id, step_run_id, payload, created_at_ms
) VALUES ($1, $2, $3, 'run.cancel_requested', $4, 'system',
'runtime:timeout', $5, NULL, $6::jsonb, $7)
`, [
command.timeoutEventId,
command.runId,
eventSequence,
timeoutDedupeKey,
command.attemptId,
JSON.stringify({
attempt_id: command.attemptId,
lease_generation: command.leaseGeneration,
reason: 'timeout',
deadline_at_ms: deadlineAtMs,
}),
observedAtMs,
]);
cancelRequestedAtMs = observedAtMs;
cancelReason = 'timeout';
}
}
if (
(cancelRequestedAtMs === undefined) !== (cancelReason === undefined) ||
(cancelReason !== undefined &&
!STOP_REASONS.has(cancelReason as RemoteWorkerStopReason))
) {
throw new TypeError('PostgreSQL Worker cancellation intent is invalid');
}
const stopReason =
cancelReason ??
(workflowTimeoutRequestedAtMs === undefined ? undefined : 'timeout');
const stopRequestedAtMs =
cancelRequestedAtMs ?? workflowTimeoutRequestedAtMs;
const nextVersion = command.expectedLeaseVersion + 1;
if (nextVersion > 2_147_483_647) {
throw new RangeError('Worker lease control version overflowed');
}
const expiresAtMs = observedAtMs + command.leaseDurationMs;
const renewed = await client.query<Row>(`
UPDATE "ql3"."run_dispatch_leases"
SET version = $2, renewed_at_ms = $3, expires_at_ms = $4,
updated_at_ms = $3
WHERE attempt_id = $1 AND status = 'leased' AND version = $5
RETURNING renewed_at_ms AS "renewedAtMs", expires_at_ms AS "expiresAtMs"
`, [
command.attemptId,
nextVersion,
observedAtMs,
expiresAtMs,
command.expectedLeaseVersion,
]);
const attempt = await client.query(`
UPDATE "ql3"."run_attempts"
SET lease_version = $2, lease_expires_at_ms = $3
WHERE id = $1 AND lease_version = $4
AND status IN ('claimed', 'starting', 'running')
`, [
command.attemptId,
nextVersion,
expiresAtMs,
command.expectedLeaseVersion,
]);
if (renewed.rows.length !== 1 || attempt.rowCount !== 1) {
reject(command, 'version_mismatch');
}
const result = {
status: stopReason === undefined
? 'renewed' as const
: 'stop_requested' as const,
...common(command),
leaseVersion: nextVersion,
renewedAtMs: integer(renewed.rows[0]!, 'renewedAtMs'),
expiresAtMs: integer(renewed.rows[0]!, 'expiresAtMs'),
...(stopReason === undefined
? {}
: {
stop: Object.freeze({
reason: stopReason as RemoteWorkerStopReason,
requestedAtMs: stopRequestedAtMs!,
}),
}),
};
return normalizeRemoteWorkerLeaseControlResult(result);
});
}
private async transaction<T>(
work: (client: PostgresClient) => Promise<T>,
): Promise<T> {
let client: PostgresClient;
try {
client = await this.pool.connect();
} catch (error) {
throw new RemoteWorkerLeaseControlUnavailableError({ cause: error });
}
try {
await begin(client);
const value = await work(client);
await client.query('COMMIT');
return value;
} catch (error) {
try {
await client.query('ROLLBACK');
} catch {
// Preserve the originating failure.
}
if (
error instanceof RemoteWorkerLeaseControlFenceRejectedError ||
error instanceof InvalidRemoteWorkerLeaseControlError
) throw error;
throw new RemoteWorkerLeaseControlUnavailableError({ cause: error });
} finally {
client.release();
}
}
}
@@ -0,0 +1,739 @@
// PostgreSQL Remote Execution dispatch leases are owned by this domain.
import type {
ClaimRunDispatchLeaseCommand,
ClaimRunDispatchLeaseResult,
PostgresClient,
PostgresPool,
ReleaseRunDispatchLeaseCommand,
RenewRunDispatchLeaseCommand,
RunDispatchLeaseRecord,
RunDispatchLeaseRepository,
RunDispatchLeaseStatus,
} from '@qinglong/runtime-core';
import {
RUN_DISPATCH_LEASE_STATUSES,
RunDispatchLeaseFenceRejectedError,
assertRunDispatchId,
assertRunDispatchLeaseDuration,
assertRunDispatchLeaseFence,
assertRunDispatchLeaseRecord,
digestRunDispatchLeaseToken,
} from '@qinglong/runtime-core';
import { lockAttemptAuthority } from '../run/attemptAuthorityLock';
type Row = Record<string, unknown>;
const LEASE_COLUMNS = `
attempt_id AS "attemptId",
run_id AS "runId",
status AS "status",
version AS "version",
lease_generation AS "leaseGeneration",
worker_id AS "workerId",
worker_session_id AS "workerSessionId",
worker_generation AS "workerGeneration",
lease_token_digest AS "leaseTokenDigest",
acquired_at_ms AS "acquiredAtMs",
renewed_at_ms AS "renewedAtMs",
expires_at_ms AS "expiresAtMs",
released_at_ms AS "releasedAtMs",
release_reason AS "releaseReason",
completed_at_ms AS "completedAtMs",
updated_at_ms AS "updatedAtMs"
`.trim();
function string(row: Row, key: string): string {
const value = row[key];
if (typeof value !== 'string' || value.length === 0) {
throw new TypeError(`PostgreSQL Run dispatch lease ${key} is invalid`);
}
return value;
}
function integer(row: Row, key: string): number {
const value = row[key];
const normalized =
typeof value === 'string' && /^(0|[1-9]\d*)$/.test(value)
? Number(value)
: value;
if (typeof normalized !== 'number' || !Number.isSafeInteger(normalized)) {
throw new TypeError(`PostgreSQL Run dispatch lease ${key} is invalid`);
}
return normalized;
}
function optionalInteger(row: Row, key: string): number | undefined {
return row[key] === null || row[key] === undefined ? undefined : integer(row, key);
}
function optionalString(row: Row, key: string): string | undefined {
return row[key] === null || row[key] === undefined ? undefined : string(row, key);
}
function lease(row: Row): RunDispatchLeaseRecord {
const status = string(row, 'status');
if (!RUN_DISPATCH_LEASE_STATUSES.includes(status as RunDispatchLeaseStatus)) {
throw new TypeError('PostgreSQL Run dispatch lease status is invalid');
}
const releasedAtMs = optionalInteger(row, 'releasedAtMs');
const releaseReason = optionalString(row, 'releaseReason');
const completedAtMs = optionalInteger(row, 'completedAtMs');
const value: RunDispatchLeaseRecord = Object.freeze({
attemptId: string(row, 'attemptId'),
runId: string(row, 'runId'),
status: status as RunDispatchLeaseStatus,
version: integer(row, 'version'),
leaseGeneration: integer(row, 'leaseGeneration'),
workerId: string(row, 'workerId'),
workerSessionId: string(row, 'workerSessionId'),
workerGeneration: integer(row, 'workerGeneration'),
leaseTokenDigest: string(row, 'leaseTokenDigest'),
acquiredAtMs: integer(row, 'acquiredAtMs'),
renewedAtMs: integer(row, 'renewedAtMs'),
expiresAtMs: integer(row, 'expiresAtMs'),
updatedAtMs: integer(row, 'updatedAtMs'),
...(releasedAtMs === undefined ? {} : { releasedAtMs }),
...(releaseReason === undefined
? {}
: {
releaseReason: releaseReason as NonNullable<
RunDispatchLeaseRecord['releaseReason']
>,
}),
...(completedAtMs === undefined ? {} : { completedAtMs }),
});
assertRunDispatchLeaseRecord(value);
return value;
}
function bounded(name: string, value: string): void {
assertRunDispatchId(name, value);
}
function assertClaim(command: ClaimRunDispatchLeaseCommand): void {
bounded('runId', command.runId);
bounded('attemptId', command.attemptId);
bounded('eventId', command.eventId);
bounded('offerId', command.offerId);
assertRunDispatchLeaseFence({
...command,
leaseGeneration: 1,
expectedVersion: 0,
});
assertRunDispatchLeaseDuration(command.leaseDurationMs);
}
function assertRenew(command: RenewRunDispatchLeaseCommand): void {
bounded('attemptId', command.attemptId);
assertRunDispatchLeaseFence(command);
assertRunDispatchLeaseDuration(command.leaseDurationMs);
}
function assertRelease(command: ReleaseRunDispatchLeaseCommand): void {
bounded('runId', command.runId);
bounded('attemptId', command.attemptId);
bounded('eventId', command.eventId);
assertRunDispatchLeaseFence(command);
if (
!['declined', 'shutdown', 'start_failed', 'capacity_changed'].includes(
command.reason,
)
) {
throw new TypeError('Run dispatch release reason is invalid');
}
}
async function begin(client: PostgresClient): Promise<void> {
await client.query('BEGIN');
await client.query("SET LOCAL statement_timeout = '5s'");
await client.query("SET LOCAL lock_timeout = '1s'");
await client.query("SET LOCAL idle_in_transaction_session_timeout = '10s'");
}
async function now(client: PostgresClient): Promise<number> {
const result = await client.query<Row>(`
SELECT floor(extract(epoch FROM statement_timestamp()) * 1000)::bigint AS "nowMs"
`);
if (result.rows.length !== 1) {
throw new TypeError('PostgreSQL Run lease observation is invalid');
}
return integer(result.rows[0]!, 'nowMs');
}
function sameFence(
current: RunDispatchLeaseRecord,
command: {
workerId: string;
workerSessionId: string;
workerGeneration: number;
leaseGeneration: number;
leaseToken: string;
},
): boolean {
return (
current.workerId === command.workerId &&
current.workerSessionId === command.workerSessionId &&
current.workerGeneration === command.workerGeneration &&
current.leaseGeneration === command.leaseGeneration &&
current.leaseTokenDigest === digestRunDispatchLeaseToken(command.leaseToken)
);
}
function assertLeaseFence(
current: RunDispatchLeaseRecord | null,
command: RenewRunDispatchLeaseCommand | ReleaseRunDispatchLeaseCommand,
observedAtMs: number,
): asserts current is RunDispatchLeaseRecord {
if (!current) throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'missing');
if ('runId' in command && current.runId !== command.runId) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'run_mismatch');
}
if (current.workerId !== command.workerId) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'worker_mismatch');
}
if (current.workerSessionId !== command.workerSessionId) {
throw new RunDispatchLeaseFenceRejectedError(
command.attemptId,
'worker_session_mismatch',
);
}
if (current.workerGeneration !== command.workerGeneration) {
throw new RunDispatchLeaseFenceRejectedError(
command.attemptId,
'worker_generation_mismatch',
);
}
if (current.leaseGeneration !== command.leaseGeneration) {
throw new RunDispatchLeaseFenceRejectedError(
command.attemptId,
'lease_generation_mismatch',
);
}
if (current.leaseTokenDigest !== digestRunDispatchLeaseToken(command.leaseToken)) {
throw new RunDispatchLeaseFenceRejectedError(
command.attemptId,
'lease_token_mismatch',
);
}
if (current.version !== command.expectedVersion) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'version_mismatch');
}
if (current.status !== 'leased') {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'not_leased');
}
if (current.expiresAtMs <= observedAtMs) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'lease_expired');
}
}
function workerCurrent(
row: Row | undefined,
command: {
workerId: string;
workerSessionId: string;
workerGeneration: number;
},
observedAtMs: number,
allowDraining: boolean,
): boolean {
return Boolean(
row &&
row.workerId === command.workerId &&
row.sessionId === command.workerSessionId &&
integer(row, 'generation') === command.workerGeneration &&
(row.status === 'online' || (allowDraining && row.status === 'draining')) &&
integer(row, 'leaseExpiresAtMs') > observedAtMs,
);
}
export class PostgresRunDispatchLeaseRepository
implements RunDispatchLeaseRepository
{
constructor(private readonly pool: PostgresPool) {}
async findByAttemptId(
attemptId: string,
): Promise<RunDispatchLeaseRecord | null> {
bounded('attemptId', attemptId);
const result = await this.pool.query<Row>(
`SELECT ${LEASE_COLUMNS} FROM "ql3"."run_dispatch_leases" WHERE attempt_id = $1`,
[attemptId],
);
if (result.rows.length > 1) {
throw new TypeError('PostgreSQL Run lease lookup returned multiple rows');
}
return result.rows[0] ? lease(result.rows[0]) : null;
}
async claim(
command: ClaimRunDispatchLeaseCommand,
): Promise<ClaimRunDispatchLeaseResult> {
assertClaim(command);
return this.transaction(async (client) => {
await lockAttemptAuthority(client, command.attemptId);
const workerResult = await client.query<Row>(
`
SELECT worker_id AS "workerId", session_id AS "sessionId",
generation, status, max_concurrent_runs AS "maxConcurrentRuns",
available_slots AS "availableSlots",
lease_expires_at_ms AS "leaseExpiresAtMs"
FROM "ql3"."worker_sessions" WHERE worker_id = $1 FOR UPDATE
`,
[command.workerId],
);
const worker = workerResult.rows[0];
const aggregateResult = await client.query<Row>(
`
SELECT run.id AS "runId", run.status AS "runStatus",
run.execution_owner AS "executionOwner",
run.cancel_requested_at_ms AS "cancelRequestedAtMs",
run.version AS "runVersion", run.event_sequence AS "eventSequence",
attempt.id AS "attemptId", attempt.status AS "attemptStatus",
attempt.run_id AS "attemptRunId",
attempt.step_run_id AS "attemptStepRunId",
workflow_task.attempt_id AS "workflowAttemptId",
workflow_task.step_run_id AS "workflowStepRunId",
workflow_task.step_run_version AS
"admittedWorkflowStepVersion",
workflow_task.step_run_digest AS
"admittedWorkflowStepDigest"
FROM "ql3"."runs" AS run
INNER JOIN "ql3"."run_attempts" AS attempt ON attempt.id = $2
LEFT JOIN
"ql3"."plugin_package_workflow_task_attempt_admissions"
AS workflow_task
ON workflow_task.attempt_id = attempt.id
WHERE run.id = $1
FOR UPDATE OF run, attempt
`,
[command.runId, command.attemptId],
);
const aggregate = aggregateResult.rows[0];
const workflowAttempt =
aggregate?.workflowAttemptId !== null &&
aggregate?.workflowAttemptId !== undefined;
const workflowStep = workflowAttempt
? (
await client.query<Row>(
`SELECT status AS "workflowStepStatus",
version AS "workflowStepVersion",
step_run_digest AS "workflowStepDigest"
FROM "ql3"."step_runs"
WHERE run_id = $1 AND id = $2
FOR UPDATE`,
[command.runId, aggregate!.workflowStepRunId],
)
).rows[0]
: undefined;
const workflowEligible = Boolean(
workflowAttempt &&
aggregate!.runStatus === 'running' &&
aggregate!.attemptStepRunId === aggregate!.workflowStepRunId &&
workflowStep?.workflowStepStatus === 'ready' &&
integer(workflowStep!, 'workflowStepVersion') ===
integer(aggregate!, 'admittedWorkflowStepVersion') &&
workflowStep!.workflowStepDigest ===
aggregate!.admittedWorkflowStepDigest,
);
const runEligible = Boolean(
!workflowAttempt &&
['queued', 'dispatching'].includes(String(aggregate?.runStatus)),
);
if (
!aggregate ||
aggregate.executionOwner !== 'runtime' ||
aggregate.cancelRequestedAtMs !== null ||
aggregate.attemptRunId !== command.runId ||
aggregate.attemptStatus !== 'claimed' ||
(!runEligible && !workflowEligible)
) {
return Object.freeze({ status: 'not_eligible' as const });
}
const currentResult = await client.query<Row>(
`SELECT ${LEASE_COLUMNS}, offer_id AS "offerId" FROM "ql3"."run_dispatch_leases" WHERE attempt_id = $1 FOR UPDATE`,
[command.attemptId],
);
const current = currentResult.rows[0] ? lease(currentResult.rows[0]) : null;
const observedAtMs = await now(client);
if (!workerCurrent(worker, command, observedAtMs, false)) {
return Object.freeze({ status: 'worker_unavailable' as const });
}
if (current && current.runId !== command.runId) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'run_mismatch');
}
if (current?.status === 'leased' && current.expiresAtMs > observedAtMs) {
if (
sameFence(current, {
...command,
leaseGeneration: current.leaseGeneration,
}) &&
currentResult.rows[0]!.offerId === command.offerId
) {
return Object.freeze({ status: 'idempotent' as const, lease: current });
}
return Object.freeze({ status: 'leased' as const, lease: current });
}
if (current?.status === 'completed') {
return Object.freeze({ status: 'not_eligible' as const });
}
const active = await client.query<Row>(
`
SELECT count(*)::integer AS "activeCount"
FROM "ql3"."run_dispatch_leases"
WHERE worker_id = $1 AND worker_session_id = $2
AND worker_generation = $3 AND status = 'leased'
AND expires_at_ms > $4 AND attempt_id <> $5
`,
[
command.workerId,
command.workerSessionId,
command.workerGeneration,
observedAtMs,
command.attemptId,
],
);
const activeCount = integer(active.rows[0]!, 'activeCount');
if (
activeCount >= integer(worker!, 'maxConcurrentRuns') ||
activeCount >= integer(worker!, 'availableSlots')
) {
return Object.freeze({ status: 'capacity_exhausted' as const });
}
const leaseGeneration = (current?.leaseGeneration ?? 0) + 1;
const version = current ? current.version + 1 : 0;
if (leaseGeneration > 2_147_483_647 || version > 2_147_483_647) {
throw new RangeError('Run dispatch lease generation or version overflowed');
}
const digest = digestRunDispatchLeaseToken(command.leaseToken);
const expiresAtMs = observedAtMs + command.leaseDurationMs;
const persisted = await client.query<Row>(
`
INSERT INTO "ql3"."run_dispatch_leases" (
attempt_id, run_id, status, version, lease_generation,
worker_id, worker_session_id, worker_generation,
lease_token_digest, offer_id, acquired_at_ms, renewed_at_ms,
expires_at_ms, released_at_ms, release_reason, completed_at_ms,
updated_at_ms
) VALUES ($1, $2, 'leased', $3, $4, $5, $6, $7, $8, $9, $10, $10, $11, NULL, NULL, NULL, $10)
ON CONFLICT (attempt_id) DO UPDATE SET
run_id = EXCLUDED.run_id,
status = EXCLUDED.status,
version = EXCLUDED.version,
lease_generation = EXCLUDED.lease_generation,
worker_id = EXCLUDED.worker_id,
worker_session_id = EXCLUDED.worker_session_id,
worker_generation = EXCLUDED.worker_generation,
lease_token_digest = EXCLUDED.lease_token_digest,
offer_id = EXCLUDED.offer_id,
acquired_at_ms = EXCLUDED.acquired_at_ms,
renewed_at_ms = EXCLUDED.renewed_at_ms,
expires_at_ms = EXCLUDED.expires_at_ms,
released_at_ms = NULL,
release_reason = NULL,
completed_at_ms = NULL,
updated_at_ms = EXCLUDED.updated_at_ms
RETURNING ${LEASE_COLUMNS}
`,
[
command.attemptId,
command.runId,
version,
leaseGeneration,
command.workerId,
command.workerSessionId,
command.workerGeneration,
digest,
command.offerId,
observedAtMs,
expiresAtMs,
],
);
const attemptUpdate = await client.query(
`
UPDATE "ql3"."run_attempts"
SET worker_id = $3, worker_session_id = $4, worker_generation = $5,
lease_token = NULL, lease_token_digest = $6,
lease_generation = $7, lease_version = $8,
lease_expires_at_ms = $9, offer_id = $10
WHERE id = $1 AND run_id = $2 AND status = 'claimed'
`,
[
command.attemptId,
command.runId,
command.workerId,
command.workerSessionId,
command.workerGeneration,
digest,
leaseGeneration,
version,
expiresAtMs,
command.offerId,
],
);
if (attemptUpdate.rowCount !== 1) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'version_mismatch');
}
const nextSequence = integer(aggregate, 'eventSequence') + 1;
const nextVersion = integer(aggregate, 'runVersion') + 1;
const eventType = workflowAttempt
? 'workflow.task_dispatch_leased'
: aggregate.runStatus === 'queued'
? 'run.dispatching'
: 'run.dispatch_reclaimed';
const runUpdate = await client.query(
`
UPDATE "ql3"."runs"
SET status = $2, version = $3, event_sequence = $4
WHERE id = $1 AND version = $5
`,
[
command.runId,
workflowAttempt ? 'running' : 'dispatching',
nextVersion,
nextSequence,
integer(aggregate, 'runVersion'),
],
);
if (runUpdate.rowCount !== 1) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'version_mismatch');
}
await client.query(
`
INSERT INTO "ql3"."run_events" (
id, run_id, sequence, type, dedupe_key, actor_type, actor_id,
attempt_id, step_run_id, payload, created_at_ms
) VALUES ($1, $2, $3, $4, $5, 'worker', $6, $7, $8, $9::jsonb, $10)
`,
[
command.eventId,
command.runId,
nextSequence,
eventType,
`run-dispatch:${command.attemptId}:${leaseGeneration}:claimed`,
command.workerId,
command.attemptId,
workflowAttempt ? aggregate.workflowStepRunId : null,
JSON.stringify({
attempt_id: command.attemptId,
lease_generation: leaseGeneration,
execution_scope: workflowAttempt ? 'workflow_task' : 'run',
from_status: workflowAttempt ? 'ready' : aggregate.runStatus,
to_status: workflowAttempt ? 'ready' : 'dispatching',
}),
observedAtMs,
],
);
if (persisted.rows.length !== 1) {
throw new TypeError('PostgreSQL Run lease claim returned no row');
}
return Object.freeze({ status: 'claimed' as const, lease: lease(persisted.rows[0]!) });
});
}
async renew(
command: RenewRunDispatchLeaseCommand,
): Promise<RunDispatchLeaseRecord> {
assertRenew(command);
return this.transaction(async (client) => {
await lockAttemptAuthority(client, command.attemptId);
const workerResult = await this.lockWorker(client, command.workerId);
const current = await this.lockLease(client, command.attemptId);
const observedAtMs = await now(client);
if (!workerCurrent(workerResult, command, observedAtMs, true)) {
throw new RunDispatchLeaseFenceRejectedError(
command.attemptId,
'worker_unavailable',
);
}
assertLeaseFence(current, command, observedAtMs);
const nextVersion = current.version + 1;
if (nextVersion > 2_147_483_647) {
throw new RangeError('Run dispatch lease version overflowed');
}
const expiresAtMs = observedAtMs + command.leaseDurationMs;
const result = await client.query<Row>(
`
UPDATE "ql3"."run_dispatch_leases"
SET version = $2, renewed_at_ms = $3, expires_at_ms = $4, updated_at_ms = $3
WHERE attempt_id = $1 AND version = $5
RETURNING ${LEASE_COLUMNS}
`,
[command.attemptId, nextVersion, observedAtMs, expiresAtMs, current.version],
);
const attempt = await client.query(
`
UPDATE "ql3"."run_attempts"
SET lease_version = $2, lease_expires_at_ms = $3
WHERE id = $1 AND worker_id = $4 AND worker_session_id = $5
AND worker_generation = $6 AND lease_generation = $7
AND lease_token_digest = $8 AND lease_version = $9
AND status IN ('claimed', 'starting', 'running')
`,
[
command.attemptId,
nextVersion,
expiresAtMs,
command.workerId,
command.workerSessionId,
command.workerGeneration,
command.leaseGeneration,
digestRunDispatchLeaseToken(command.leaseToken),
command.expectedVersion,
],
);
if (result.rows.length !== 1 || attempt.rowCount !== 1) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'version_mismatch');
}
return lease(result.rows[0]!);
});
}
async release(
command: ReleaseRunDispatchLeaseCommand,
): Promise<RunDispatchLeaseRecord> {
assertRelease(command);
return this.transaction(async (client) => {
await lockAttemptAuthority(client, command.attemptId);
const worker = await this.lockWorker(client, command.workerId);
const current = await this.lockLease(client, command.attemptId);
const aggregate = await client.query<Row>(
`
SELECT run.version AS "runVersion", run.event_sequence AS "eventSequence",
attempt.status AS "attemptStatus",
workflow_task.step_run_id AS "workflowStepRunId"
FROM "ql3"."runs" AS run
INNER JOIN "ql3"."run_attempts" AS attempt ON attempt.id = $2
LEFT JOIN
"ql3"."plugin_package_workflow_task_attempt_admissions"
AS workflow_task
ON workflow_task.attempt_id = attempt.id
WHERE run.id = $1 AND attempt.run_id = run.id
FOR UPDATE OF run, attempt
`,
[command.runId, command.attemptId],
);
const observedAtMs = await now(client);
if (!workerCurrent(worker, command, observedAtMs, true)) {
throw new RunDispatchLeaseFenceRejectedError(
command.attemptId,
'worker_unavailable',
);
}
assertLeaseFence(current, command, observedAtMs);
if (aggregate.rows[0]?.attemptStatus !== 'claimed') {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'not_leased');
}
const nextVersion = current.version + 1;
const result = await client.query<Row>(
`
UPDATE "ql3"."run_dispatch_leases"
SET status = 'released', version = $2, released_at_ms = $3,
release_reason = $4, completed_at_ms = NULL, updated_at_ms = $3
WHERE attempt_id = $1 AND version = $5
RETURNING ${LEASE_COLUMNS}
`,
[command.attemptId, nextVersion, observedAtMs, command.reason, current.version],
);
const attempt = await client.query(
`
UPDATE "ql3"."run_attempts"
SET worker_id = NULL, worker_session_id = NULL, worker_generation = NULL,
lease_token = NULL, lease_token_digest = NULL,
lease_generation = NULL, lease_version = NULL,
lease_expires_at_ms = NULL, offer_id = NULL
WHERE id = $1 AND lease_version = $2
`,
[command.attemptId, command.expectedVersion],
);
const aggregateRow = aggregate.rows[0]!;
const workflowStepRunId = optionalString(
aggregateRow,
'workflowStepRunId',
);
const runVersion = integer(aggregateRow, 'runVersion');
const eventSequence = integer(aggregateRow, 'eventSequence') + 1;
const run = await client.query(
`UPDATE "ql3"."runs" SET version = $2, event_sequence = $3 WHERE id = $1 AND version = $4`,
[command.runId, runVersion + 1, eventSequence, runVersion],
);
if (result.rows.length !== 1 || attempt.rowCount !== 1 || run.rowCount !== 1) {
throw new RunDispatchLeaseFenceRejectedError(command.attemptId, 'version_mismatch');
}
await client.query(
`
INSERT INTO "ql3"."run_events" (
id, run_id, sequence, type, dedupe_key, actor_type, actor_id,
attempt_id, step_run_id, payload, created_at_ms
) VALUES ($1, $2, $3, $4, $5, 'worker', $6, $7, $8, $9::jsonb, $10)
`,
[
command.eventId,
command.runId,
eventSequence,
workflowStepRunId
? 'workflow.task_dispatch_released'
: 'run.dispatch_released',
`run-dispatch:${command.attemptId}:${command.leaseGeneration}:released`,
command.workerId,
command.attemptId,
workflowStepRunId ?? null,
JSON.stringify({
attempt_id: command.attemptId,
lease_generation: command.leaseGeneration,
execution_scope: workflowStepRunId ? 'workflow_task' : 'run',
reason: command.reason,
}),
observedAtMs,
],
);
return lease(result.rows[0]!);
});
}
private async lockWorker(
client: PostgresClient,
workerId: string,
): Promise<Row | undefined> {
const result = await client.query<Row>(
`
SELECT worker_id AS "workerId", session_id AS "sessionId",
generation, status, lease_expires_at_ms AS "leaseExpiresAtMs"
FROM "ql3"."worker_sessions" WHERE worker_id = $1 FOR UPDATE
`,
[workerId],
);
return result.rows[0];
}
private async lockLease(
client: PostgresClient,
attemptId: string,
): Promise<RunDispatchLeaseRecord | null> {
const result = await client.query<Row>(
`SELECT ${LEASE_COLUMNS} FROM "ql3"."run_dispatch_leases" WHERE attempt_id = $1 FOR UPDATE`,
[attemptId],
);
return result.rows[0] ? lease(result.rows[0]) : null;
}
private async transaction<T>(
work: (client: PostgresClient) => Promise<T>,
): Promise<T> {
const client = await this.pool.connect();
try {
await begin(client);
const result = await work(client);
await client.query('COMMIT');
return result;
} catch (error) {
try {
await client.query('ROLLBACK');
} catch {
// Preserve the originating failure.
}
throw error;
} finally {
client.release();
}
}
}
@@ -0,0 +1,251 @@
// PostgreSQL Worker execution attestations are owned by this domain.
import {
WorkerExecutionAttestationFenceRejectedError,
WorkerExecutionAttestationUnavailableError,
normalizeSubmitWorkerExecutionAttestationCommand,
normalizeWorkerExecutionAttestation,
type SubmitWorkerExecutionAttestationCommand,
type SubmitWorkerExecutionAttestationResult,
type WorkerExecutionAttestationRecord,
type WorkerExecutionAttestationRepository,
} from '@qinglong/runtime-core/worker-attestation';
import type { PostgresClient, PostgresPool } from '@qinglong/runtime-core';
import { lockAttemptAuthority } from '../run/attemptAuthorityLock';
type Row = Record<string, unknown>;
const COLUMNS = `
attestation_id AS "attestationId", run_id AS "runId",
attempt_id AS "attemptId", sequence, state, worker_id AS "workerId",
worker_session_id AS "workerSessionId",
worker_generation AS "workerGeneration",
lease_token_digest AS "leaseTokenDigest",
lease_generation AS "leaseGeneration", lease_version AS "leaseVersion",
offer_id AS "offerId", callback_sequence AS "callbackSequence",
executor_handle AS "executorHandle", journal_revision AS "journalRevision",
received_at_ms AS "receivedAtMs"
`.trim();
function text(row: Row, key: string): string {
const value = row[key];
if (typeof value !== 'string' || value.length < 1) {
throw new TypeError(`PostgreSQL Worker attestation ${key} is invalid`);
}
return value;
}
function integer(row: Row, key: string): number {
const raw = row[key];
const value = typeof raw === 'string' && /^\d+$/.test(raw) ? Number(raw) : raw;
if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
throw new TypeError(`PostgreSQL Worker attestation ${key} is invalid`);
}
return value;
}
function record(row: Row): Readonly<WorkerExecutionAttestationRecord> {
return normalizeWorkerExecutionAttestation({
attestationId: text(row, 'attestationId'),
runId: text(row, 'runId'),
attemptId: text(row, 'attemptId'),
sequence: integer(row, 'sequence'),
state: text(row, 'state') as WorkerExecutionAttestationRecord['state'],
workerId: text(row, 'workerId'),
workerSessionId: text(row, 'workerSessionId'),
workerGeneration: integer(row, 'workerGeneration'),
leaseTokenDigest: text(row, 'leaseTokenDigest'),
leaseGeneration: integer(row, 'leaseGeneration'),
leaseVersion: integer(row, 'leaseVersion'),
offerId: text(row, 'offerId'),
callbackSequence: integer(row, 'callbackSequence'),
executorHandle: text(row, 'executorHandle'),
journalRevision: integer(row, 'journalRevision'),
receivedAtMs: integer(row, 'receivedAtMs'),
});
}
function sameCommand(
current: Readonly<WorkerExecutionAttestationRecord>,
command: Readonly<SubmitWorkerExecutionAttestationCommand>,
): boolean {
const { receivedAtMs: _receivedAtMs, ...semantic } = current;
return JSON.stringify(semantic) === JSON.stringify(command);
}
async function begin(client: PostgresClient): Promise<void> {
await client.query('BEGIN');
await client.query("SET LOCAL statement_timeout = '5s'");
await client.query("SET LOCAL lock_timeout = '1s'");
await client.query("SET LOCAL idle_in_transaction_session_timeout = '10s'");
}
export class PostgresWorkerExecutionAttestationRepository
implements WorkerExecutionAttestationRepository
{
constructor(private readonly pool: PostgresPool) {}
async submit(
input: SubmitWorkerExecutionAttestationCommand,
): Promise<SubmitWorkerExecutionAttestationResult> {
const command = normalizeSubmitWorkerExecutionAttestationCommand(input);
const client = await this.pool.connect();
try {
await begin(client);
await lockAttemptAuthority(client, command.attemptId);
const replayResult = await client.query<Row>(
`SELECT ${COLUMNS} FROM "ql3"."worker_execution_attestations" WHERE attestation_id = $1`,
[command.attestationId],
);
if (replayResult.rows.length > 1) {
throw new WorkerExecutionAttestationUnavailableError();
}
if (replayResult.rows[0]) {
const current = record(replayResult.rows[0]);
if (!sameCommand(current, command)) {
throw new WorkerExecutionAttestationFenceRejectedError('attestation_id_conflict');
}
await client.query('COMMIT');
return Object.freeze({ status: 'existing', attestation: current });
}
const authority = await client.query<Row>(
`
SELECT attempt.run_id AS "attemptRunId", attempt.status AS "attemptStatus",
attempt.worker_id AS "attemptWorkerId",
attempt.worker_session_id AS "attemptWorkerSessionId",
attempt.worker_generation AS "attemptWorkerGeneration",
attempt.lease_token_digest AS "attemptLeaseTokenDigest",
attempt.lease_generation AS "attemptLeaseGeneration",
attempt.lease_version AS "attemptLeaseVersion",
attempt.offer_id AS "attemptOfferId",
attempt.callback_sequence AS "attemptCallbackSequence",
attempt.executor_handle AS "attemptExecutorHandle",
session.session_id AS "sessionId",
session.generation AS "sessionGeneration",
lease.run_id AS "leaseRunId", lease.status AS "leaseStatus",
lease.worker_id AS "leaseWorkerId",
lease.worker_session_id AS "leaseWorkerSessionId",
lease.worker_generation AS "leaseWorkerGeneration",
lease.lease_token_digest AS "leaseTokenDigest",
lease.lease_generation AS "leaseGeneration",
lease.version AS "leaseVersion", lease.offer_id AS "leaseOfferId"
FROM "ql3"."run_attempts" AS attempt
JOIN "ql3"."run_dispatch_leases" AS lease ON lease.attempt_id = attempt.id
JOIN "ql3"."worker_sessions" AS session ON session.worker_id = lease.worker_id
WHERE attempt.id = $1
`,
[command.attemptId],
);
const row = authority.rows[0];
const matches =
row &&
row.attemptRunId === command.runId &&
(row.attemptStatus === 'starting' || row.attemptStatus === 'running') &&
row.attemptWorkerId === command.workerId &&
row.attemptWorkerSessionId === command.workerSessionId &&
integer(row, 'attemptWorkerGeneration') === command.workerGeneration &&
row.attemptLeaseTokenDigest === command.leaseTokenDigest &&
integer(row, 'attemptLeaseGeneration') === command.leaseGeneration &&
integer(row, 'attemptLeaseVersion') === command.leaseVersion &&
row.attemptOfferId === command.offerId &&
integer(row, 'attemptCallbackSequence') === command.callbackSequence &&
row.attemptExecutorHandle === command.executorHandle &&
row.sessionId === command.workerSessionId &&
integer(row, 'sessionGeneration') === command.workerGeneration &&
row.leaseRunId === command.runId &&
row.leaseStatus === 'leased' &&
row.leaseWorkerId === command.workerId &&
row.leaseWorkerSessionId === command.workerSessionId &&
integer(row, 'leaseWorkerGeneration') === command.workerGeneration &&
row.leaseTokenDigest === command.leaseTokenDigest &&
integer(row, 'leaseGeneration') === command.leaseGeneration &&
integer(row, 'leaseVersion') === command.leaseVersion &&
row.leaseOfferId === command.offerId;
if (!matches) {
throw new WorkerExecutionAttestationFenceRejectedError('authority_mismatch');
}
const previous = await client.query<Row>(
`
SELECT sequence, state, journal_revision AS "journalRevision"
FROM "ql3"."worker_execution_attestations"
WHERE attempt_id = $1 AND lease_generation = $2
ORDER BY sequence DESC LIMIT 1
`,
[command.attemptId, command.leaseGeneration],
);
const last = previous.rows[0];
if (
command.sequence !== (last ? integer(last, 'sequence') + 1 : 1) ||
(last && integer(last, 'journalRevision') >= command.journalRevision) ||
(last?.state === 'stopped' && command.state !== 'stopped')
) {
throw new WorkerExecutionAttestationFenceRejectedError('sequence_mismatch');
}
const nowResult = await client.query<Row>(
`SELECT floor(extract(epoch FROM statement_timestamp()) * 1000)::bigint AS "receivedAtMs"`,
);
const receivedAtMs = integer(nowResult.rows[0]!, 'receivedAtMs');
const inserted = await client.query<Row>(
`
INSERT INTO "ql3"."worker_execution_attestations" (
attestation_id, run_id, attempt_id, sequence, state, worker_id,
worker_session_id, worker_generation, lease_token_digest,
lease_generation, lease_version, offer_id, callback_sequence,
executor_handle, journal_revision, received_at_ms
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16
) RETURNING ${COLUMNS}
`,
[
command.attestationId, command.runId, command.attemptId,
command.sequence, command.state, command.workerId,
command.workerSessionId, command.workerGeneration,
command.leaseTokenDigest, command.leaseGeneration,
command.leaseVersion, command.offerId, command.callbackSequence,
command.executorHandle, command.journalRevision, receivedAtMs,
],
);
const attestation = record(inserted.rows[0]!);
await client.query('COMMIT');
return Object.freeze({ status: 'created', attestation });
} catch (error) {
try { await client.query('ROLLBACK'); } catch { /* preserve root */ }
if (
error instanceof WorkerExecutionAttestationFenceRejectedError ||
error instanceof WorkerExecutionAttestationUnavailableError
) throw error;
throw new WorkerExecutionAttestationUnavailableError();
} finally {
client.release();
}
}
async findLatestExact(
target: Parameters<WorkerExecutionAttestationRepository['findLatestExact']>[0],
): Promise<Readonly<WorkerExecutionAttestationRecord> | null> {
const result = await this.pool.query<Row>(
`
SELECT ${COLUMNS}
FROM "ql3"."worker_execution_attestations"
WHERE run_id = $1 AND attempt_id = $2 AND worker_id = $3
AND worker_session_id = $4 AND worker_generation = $5
AND lease_token_digest = $6 AND lease_generation = $7
AND lease_version = $8 AND offer_id = $9
AND callback_sequence = $10 AND executor_handle = $11
ORDER BY sequence DESC LIMIT 1
`,
[
target.runId, target.attemptId, target.workerId,
target.workerSessionId, target.workerGeneration,
target.leaseTokenDigest, target.leaseGeneration, target.leaseVersion,
target.offerId, target.callbackSequence, target.executorHandle,
],
);
try {
return result.rows[0] ? record(result.rows[0]) : null;
} catch {
throw new WorkerExecutionAttestationUnavailableError();
}
}
}
@@ -0,0 +1,675 @@
// PostgreSQL Remote Worker sessions are owned by this domain.
import type {
AvailableWorkerSessionPage,
HeartbeatWorkerSessionCommand,
PostgresClient,
PostgresPool,
RegisterWorkerSessionCommand,
RegisterWorkerSessionResult,
TransitionWorkerSessionCommand,
WorkerSessionRecord,
WorkerSessionRepository,
WorkerSessionStatus,
} from '@qinglong/runtime-core';
import {
MAX_AVAILABLE_WORKER_PAGE_SIZE,
MAX_WORKER_CONCURRENT_RUNS,
WORKER_SESSION_STATUSES,
WorkerSessionConflictError,
WorkerSessionFenceRejectedError,
assertWorkerCapabilitiesSnapshot,
assertWorkerConcurrency,
assertWorkerId,
assertWorkerSessionId,
assertWorkerSessionLeaseDuration,
assertWorkerSessionRecord,
} from '@qinglong/runtime-core';
import {
WorkerCredentialDeliveryConflictError,
WorkerCredentialDeliveryUnavailableError,
normalizeAuthenticatedWorkerCredentialIdentity,
normalizeWorkerCredentialDeliveryRecord,
type AuthenticatedWorkerCredentialIdentity,
type AuthenticatedWorkerSessionRepository,
type WorkerCredentialDeliveryRecord,
} from '@qinglong/runtime-core/worker-credential-delivery';
type Row = Record<string, unknown>;
interface DeliveryRow extends Row {
deliveryId: unknown;
version: unknown;
state: unknown;
workerId: unknown;
credentialId: unknown;
credentialVersion: unknown;
previousCredentialId: unknown;
secretDigest: unknown;
tokenDigest: unknown;
deploymentTargetDigest: unknown;
deploymentGeneration: unknown;
stagedAtMs: unknown;
credentialCommittedAtMs: unknown;
publishedAtMs: unknown;
publicationDigest: unknown;
observedAtMs: unknown;
observedSessionId: unknown;
observedSessionVersion: unknown;
previousRevokedAtMs: unknown;
}
const SELECT_COLUMNS = `
worker_id AS "workerId",
session_id AS "sessionId",
generation AS "generation",
status AS "status",
version AS "version",
capabilities_json AS "capabilitiesJson",
capabilities_hash AS "capabilitiesHash",
max_concurrent_runs AS "maxConcurrentRuns",
available_slots AS "availableSlots",
registered_at_ms AS "registeredAtMs",
last_heartbeat_at_ms AS "lastHeartbeatAtMs",
lease_expires_at_ms AS "leaseExpiresAtMs",
updated_at_ms AS "updatedAtMs"
`.trim();
const DELIVERY_COLUMNS = `
delivery_id AS "deliveryId", version, state,
worker_id AS "workerId", credential_id AS "credentialId",
credential_version AS "credentialVersion",
previous_credential_id AS "previousCredentialId",
secret_digest AS "secretDigest", token_digest AS "tokenDigest",
deployment_target_digest AS "deploymentTargetDigest",
deployment_generation AS "deploymentGeneration",
staged_at_ms AS "stagedAtMs",
credential_committed_at_ms AS "credentialCommittedAtMs",
published_at_ms AS "publishedAtMs",
publication_digest AS "publicationDigest",
observed_at_ms AS "observedAtMs",
observed_session_id AS "observedSessionId",
observed_session_version AS "observedSessionVersion",
previous_revoked_at_ms AS "previousRevokedAtMs"
`.trim();
function string(row: Row, key: string): string {
const value = row[key];
if (typeof value !== 'string' || value.length === 0) {
throw new TypeError(`PostgreSQL Worker session ${key} is invalid`);
}
return value;
}
function integer(row: Row, key: string): number {
const value = row[key];
const normalized =
typeof value === 'string' && /^(0|[1-9]\d*)$/.test(value)
? Number(value)
: value;
if (typeof normalized !== 'number' || !Number.isSafeInteger(normalized)) {
throw new TypeError(`PostgreSQL Worker session ${key} is invalid`);
}
return normalized;
}
function nullableString(row: Row, key: string): string | null {
return row[key] === null ? null : string(row, key);
}
function nullableInteger(row: Row, key: string): number | null {
return row[key] === null ? null : integer(row, key);
}
function deliveryRecord(
row: DeliveryRow,
): Readonly<WorkerCredentialDeliveryRecord> {
return normalizeWorkerCredentialDeliveryRecord({
deliveryId: string(row, 'deliveryId'),
version: integer(row, 'version'),
state: string(row, 'state') as WorkerCredentialDeliveryRecord['state'],
workerId: string(row, 'workerId'),
credentialId: string(row, 'credentialId'),
credentialVersion: integer(row, 'credentialVersion'),
previousCredentialId: nullableString(row, 'previousCredentialId'),
secretDigest: string(row, 'secretDigest'),
tokenDigest: string(row, 'tokenDigest'),
deploymentTargetDigest: string(row, 'deploymentTargetDigest'),
deploymentGeneration: string(row, 'deploymentGeneration'),
stagedAtMs: integer(row, 'stagedAtMs'),
credentialCommittedAtMs: integer(row, 'credentialCommittedAtMs'),
publishedAtMs: nullableInteger(row, 'publishedAtMs'),
publicationDigest: nullableString(row, 'publicationDigest'),
observedAtMs: nullableInteger(row, 'observedAtMs'),
observedSessionId: nullableString(row, 'observedSessionId'),
observedSessionVersion: nullableInteger(row, 'observedSessionVersion'),
previousRevokedAtMs: nullableInteger(row, 'previousRevokedAtMs'),
});
}
function sameDeliveryIdentity(
current: Readonly<WorkerCredentialDeliveryRecord>,
previous: Readonly<WorkerCredentialDeliveryRecord>,
): boolean {
return (
current.deliveryId === previous.deliveryId &&
current.workerId === previous.workerId &&
current.credentialId === previous.credentialId &&
current.credentialVersion === previous.credentialVersion &&
current.previousCredentialId === previous.previousCredentialId &&
current.secretDigest === previous.secretDigest &&
current.tokenDigest === previous.tokenDigest &&
current.deploymentTargetDigest === previous.deploymentTargetDigest &&
current.deploymentGeneration === previous.deploymentGeneration &&
current.stagedAtMs === previous.stagedAtMs &&
current.credentialCommittedAtMs === previous.credentialCommittedAtMs
);
}
async function observeCredentialDelivery(
client: PostgresClient,
requestedCredential: AuthenticatedWorkerCredentialIdentity,
worker: Readonly<WorkerSessionRecord>,
nowMs: number,
): Promise<void> {
const credential = normalizeAuthenticatedWorkerCredentialIdentity(
requestedCredential,
);
if (credential.workerId !== worker.workerId || worker.version < 1) {
throw new WorkerCredentialDeliveryConflictError();
}
const result = await client.query<DeliveryRow>(
`SELECT ${DELIVERY_COLUMNS}
FROM "ql3"."worker_credential_deliveries"
WHERE worker_id = $1
AND credential_id = $2
AND credential_version = $3
ORDER BY delivery_id ASC, version ASC
LIMIT 5`,
[credential.workerId, credential.credentialId, credential.credentialVersion],
);
if (result.rows.length === 0) return;
if (result.rows.length > 4) {
throw new WorkerCredentialDeliveryConflictError();
}
const records = result.rows.map(deliveryRecord);
for (let index = 0; index < records.length; index += 1) {
const current = records[index]!;
const previous = records[index - 1];
if (current.version !== index + 1) {
throw new WorkerCredentialDeliveryConflictError();
}
if (!previous) continue;
if (
!sameDeliveryIdentity(current, previous) ||
(current.version >= 3 &&
(current.publishedAtMs !== previous.publishedAtMs ||
current.publicationDigest !== previous.publicationDigest)) ||
(current.version >= 4 &&
(current.observedAtMs !== previous.observedAtMs ||
current.observedSessionId !== previous.observedSessionId ||
current.observedSessionVersion !== previous.observedSessionVersion))
) {
throw new WorkerCredentialDeliveryConflictError();
}
}
const latest = records.at(-1)!;
if (latest.state === 'credential_committed') {
throw new WorkerCredentialDeliveryUnavailableError();
}
if (latest.state !== 'published') return;
const observed = normalizeWorkerCredentialDeliveryRecord({
...latest,
version: 3,
state: 'observed',
observedAtMs: nowMs,
observedSessionId: worker.sessionId,
observedSessionVersion: worker.version,
});
await client.query(
`INSERT INTO "ql3"."worker_credential_deliveries" (
delivery_id, version, state, worker_id, credential_id,
credential_version, previous_credential_id, secret_digest,
token_digest, deployment_target_digest, deployment_generation,
staged_at_ms, credential_committed_at_ms, published_at_ms,
publication_digest, observed_at_ms, observed_session_id,
observed_session_version, previous_revoked_at_ms
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
$11, $12, $13, $14, $15, $16, $17, $18, $19
)`,
[
observed.deliveryId, observed.version, observed.state,
observed.workerId, observed.credentialId, observed.credentialVersion,
observed.previousCredentialId, observed.secretDigest,
observed.tokenDigest, observed.deploymentTargetDigest,
observed.deploymentGeneration, observed.stagedAtMs,
observed.credentialCommittedAtMs, observed.publishedAtMs,
observed.publicationDigest, observed.observedAtMs,
observed.observedSessionId, observed.observedSessionVersion,
observed.previousRevokedAtMs,
],
);
}
function record(row: Row): WorkerSessionRecord {
const status = string(row, 'status');
if (!WORKER_SESSION_STATUSES.includes(status as WorkerSessionStatus)) {
throw new TypeError('PostgreSQL Worker session status is invalid');
}
const result: WorkerSessionRecord = Object.freeze({
workerId: string(row, 'workerId'),
sessionId: string(row, 'sessionId'),
generation: integer(row, 'generation'),
status: status as WorkerSessionStatus,
version: integer(row, 'version'),
capabilitiesJson: string(row, 'capabilitiesJson'),
capabilitiesHash: string(row, 'capabilitiesHash'),
maxConcurrentRuns: integer(row, 'maxConcurrentRuns'),
availableSlots: integer(row, 'availableSlots'),
registeredAtMs: integer(row, 'registeredAtMs'),
lastHeartbeatAtMs: integer(row, 'lastHeartbeatAtMs'),
leaseExpiresAtMs: integer(row, 'leaseExpiresAtMs'),
updatedAtMs: integer(row, 'updatedAtMs'),
});
assertWorkerSessionRecord(result);
return result;
}
function assertRegister(command: RegisterWorkerSessionCommand): void {
assertWorkerId(command.workerId);
assertWorkerSessionId(command.sessionId);
assertWorkerCapabilitiesSnapshot(
command.capabilitiesJson,
command.capabilitiesHash,
);
assertWorkerConcurrency(command.maxConcurrentRuns, command.availableSlots);
assertWorkerSessionLeaseDuration(command.leaseDurationMs);
}
function assertHeartbeat(command: HeartbeatWorkerSessionCommand): void {
assertWorkerId(command.workerId);
assertWorkerSessionId(command.sessionId);
if (
!Number.isSafeInteger(command.availableSlots) ||
command.availableSlots < 0 ||
command.availableSlots > MAX_WORKER_CONCURRENT_RUNS
) {
throw new RangeError('Worker heartbeat availableSlots is invalid');
}
for (const [name, value, minimum] of [
['generation', command.generation, 1],
['expectedVersion', command.expectedVersion, 0],
] as const) {
if (!Number.isSafeInteger(value) || value < minimum) {
throw new RangeError(`Worker heartbeat ${name} is invalid`);
}
}
assertWorkerSessionLeaseDuration(command.leaseDurationMs);
}
function assertTransition(command: TransitionWorkerSessionCommand): void {
assertWorkerId(command.workerId);
assertWorkerSessionId(command.sessionId);
if (command.status !== 'draining' && command.status !== 'offline') {
throw new TypeError('Worker transition status is invalid');
}
if (
!Number.isSafeInteger(command.generation) ||
command.generation < 1 ||
!Number.isSafeInteger(command.expectedVersion) ||
command.expectedVersion < 0
) {
throw new RangeError('Worker transition fence is invalid');
}
}
async function begin(client: PostgresClient): Promise<void> {
await client.query('BEGIN');
await client.query("SET LOCAL statement_timeout = '5s'");
await client.query("SET LOCAL lock_timeout = '1s'");
await client.query("SET LOCAL idle_in_transaction_session_timeout = '10s'");
}
async function observedAtMs(client: PostgresClient): Promise<number> {
const result = await client.query<Row>(`
SELECT floor(extract(epoch FROM statement_timestamp()) * 1000)::bigint
AS "observedAtMs"
`);
if (result.rows.length !== 1) {
throw new TypeError('PostgreSQL Worker observation is invalid');
}
return integer(result.rows[0]!, 'observedAtMs');
}
function fence(
current: WorkerSessionRecord | null,
command: {
workerId: string;
sessionId: string;
generation: number;
expectedVersion: number;
},
nowMs: number,
): void {
if (!current) throw new WorkerSessionFenceRejectedError(command.workerId, 'missing');
if (current.sessionId !== command.sessionId) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'session_mismatch');
}
if (current.generation !== command.generation) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'generation_mismatch');
}
if (current.version !== command.expectedVersion) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'version_mismatch');
}
if (current.status === 'offline') {
throw new WorkerSessionFenceRejectedError(command.workerId, 'offline');
}
if (current.leaseExpiresAtMs <= nowMs) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'lease_expired');
}
}
export class PostgresWorkerSessionRepository
implements WorkerSessionRepository, AuthenticatedWorkerSessionRepository
{
constructor(private readonly pool: PostgresPool) {}
async findById(workerId: string): Promise<WorkerSessionRecord | null> {
assertWorkerId(workerId);
const result = await this.pool.query<Row>(
`SELECT ${SELECT_COLUMNS} FROM "ql3"."worker_sessions" WHERE worker_id = $1`,
[workerId],
);
if (result.rows.length > 1) {
throw new TypeError('PostgreSQL Worker lookup returned multiple rows');
}
return result.rows[0] ? record(result.rows[0]) : null;
}
async register(
command: RegisterWorkerSessionCommand,
): Promise<RegisterWorkerSessionResult> {
assertRegister(command);
const client = await this.pool.connect();
try {
await begin(client);
await client.query(
`SELECT pg_advisory_xact_lock(hashtextextended($1, 684022785147727641::bigint))`,
[command.workerId],
);
const currentResult = await client.query<Row>(
`SELECT ${SELECT_COLUMNS} FROM "ql3"."worker_sessions" WHERE worker_id = $1 FOR UPDATE`,
[command.workerId],
);
const current = currentResult.rows[0] ? record(currentResult.rows[0]) : null;
const nowMs = await observedAtMs(client);
if (current?.sessionId === command.sessionId) {
if (
current.capabilitiesJson !== command.capabilitiesJson ||
current.capabilitiesHash !== command.capabilitiesHash ||
current.maxConcurrentRuns !== command.maxConcurrentRuns ||
current.availableSlots !== command.availableSlots
) {
throw new WorkerSessionConflictError(command.workerId);
}
if (current.status === 'offline') {
throw new WorkerSessionFenceRejectedError(command.workerId, 'offline');
}
if (current.leaseExpiresAtMs <= nowMs) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'lease_expired');
}
await client.query('COMMIT');
return Object.freeze({ worker: current, replacedSession: false });
}
const generation = current ? current.generation + 1 : 1;
const version = current ? current.version + 1 : 0;
if (generation > 2_147_483_647 || version > 2_147_483_647) {
throw new RangeError('Worker session generation or version overflowed');
}
const expiresAtMs = nowMs + command.leaseDurationMs;
const result = await client.query<Row>(
`
INSERT INTO "ql3"."worker_sessions" (
worker_id, session_id, generation, status, version,
capabilities_json, capabilities_hash, max_concurrent_runs,
available_slots, registered_at_ms, last_heartbeat_at_ms,
lease_expires_at_ms, updated_at_ms
) VALUES ($1, $2, $3, 'online', $4, $5, $6, $7, $8, $9, $9, $10, $9)
ON CONFLICT (worker_id) DO UPDATE SET
session_id = EXCLUDED.session_id,
generation = EXCLUDED.generation,
status = EXCLUDED.status,
version = EXCLUDED.version,
capabilities_json = EXCLUDED.capabilities_json,
capabilities_hash = EXCLUDED.capabilities_hash,
max_concurrent_runs = EXCLUDED.max_concurrent_runs,
available_slots = EXCLUDED.available_slots,
registered_at_ms = EXCLUDED.registered_at_ms,
last_heartbeat_at_ms = EXCLUDED.last_heartbeat_at_ms,
lease_expires_at_ms = EXCLUDED.lease_expires_at_ms,
updated_at_ms = EXCLUDED.updated_at_ms
RETURNING ${SELECT_COLUMNS}
`,
[
command.workerId,
command.sessionId,
generation,
version,
command.capabilitiesJson,
command.capabilitiesHash,
command.maxConcurrentRuns,
command.availableSlots,
nowMs,
expiresAtMs,
],
);
if (result.rows.length !== 1) {
throw new TypeError('PostgreSQL Worker registration returned no row');
}
await client.query('COMMIT');
return Object.freeze({
worker: record(result.rows[0]!),
replacedSession: current !== null,
});
} catch (error) {
try {
await client.query('ROLLBACK');
} catch {
// Preserve the originating failure.
}
throw error;
} finally {
client.release();
}
}
async heartbeat(
command: HeartbeatWorkerSessionCommand,
): Promise<WorkerSessionRecord> {
return this.heartbeatInternal(command);
}
async heartbeatAuthenticated(
command: HeartbeatWorkerSessionCommand,
credential: AuthenticatedWorkerCredentialIdentity,
): Promise<WorkerSessionRecord> {
return this.heartbeatInternal(command, credential);
}
private async heartbeatInternal(
command: HeartbeatWorkerSessionCommand,
credential?: AuthenticatedWorkerCredentialIdentity,
): Promise<WorkerSessionRecord> {
assertHeartbeat(command);
return this.mutate(command.workerId, async (client, nowMs, current) => {
fence(current, command, nowMs);
if (!current) throw new WorkerSessionFenceRejectedError(command.workerId, 'missing');
assertWorkerConcurrency(current.maxConcurrentRuns, command.availableSlots);
const result = await client.query<Row>(
`
UPDATE "ql3"."worker_sessions"
SET version = version + 1,
available_slots = CASE WHEN status = 'draining' THEN 0 ELSE $5 END,
last_heartbeat_at_ms = $6,
lease_expires_at_ms = $7,
updated_at_ms = $6
WHERE worker_id = $1 AND session_id = $2 AND generation = $3 AND version = $4
RETURNING ${SELECT_COLUMNS}
`,
[
command.workerId,
command.sessionId,
command.generation,
command.expectedVersion,
command.availableSlots,
nowMs,
nowMs + command.leaseDurationMs,
],
);
if (result.rows.length !== 1) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'version_mismatch');
}
const worker = record(result.rows[0]!);
if (credential) {
await observeCredentialDelivery(client, credential, worker, nowMs);
}
return worker;
});
}
async transition(
command: TransitionWorkerSessionCommand,
): Promise<WorkerSessionRecord> {
return this.transitionInternal(command);
}
async transitionAuthenticated(
command: TransitionWorkerSessionCommand,
credential: AuthenticatedWorkerCredentialIdentity,
): Promise<WorkerSessionRecord> {
return this.transitionInternal(command, credential);
}
private async transitionInternal(
command: TransitionWorkerSessionCommand,
credential?: AuthenticatedWorkerCredentialIdentity,
): Promise<WorkerSessionRecord> {
assertTransition(command);
return this.mutate(command.workerId, async (client, nowMs, current) => {
fence(current, command, nowMs);
const result = await client.query<Row>(
`
UPDATE "ql3"."worker_sessions"
SET version = version + 1,
status = $5::varchar,
available_slots = 0,
lease_expires_at_ms = CASE
WHEN $5::varchar = 'offline' THEN $6
ELSE lease_expires_at_ms
END,
updated_at_ms = $6
WHERE worker_id = $1 AND session_id = $2 AND generation = $3 AND version = $4
RETURNING ${SELECT_COLUMNS}
`,
[
command.workerId,
command.sessionId,
command.generation,
command.expectedVersion,
command.status,
nowMs,
],
);
if (result.rows.length !== 1) {
throw new WorkerSessionFenceRejectedError(command.workerId, 'version_mismatch');
}
const worker = record(result.rows[0]!);
if (credential) {
await observeCredentialDelivery(client, credential, worker, nowMs);
}
return worker;
});
}
async listAvailable(
options: Readonly<{ afterWorkerId?: string; limit?: number }> = {},
): Promise<AvailableWorkerSessionPage> {
const limit = options.limit ?? 16;
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_AVAILABLE_WORKER_PAGE_SIZE) {
throw new RangeError(
`Worker page limit must be between 1 and ${MAX_AVAILABLE_WORKER_PAGE_SIZE}`,
);
}
if (options.afterWorkerId !== undefined) assertWorkerId(options.afterWorkerId);
const result = await this.pool.query<Row>(
`
WITH observation AS (
SELECT floor(extract(epoch FROM statement_timestamp()) * 1000)::bigint AS observed_at_ms
), available AS (
SELECT ${SELECT_COLUMNS}
FROM "ql3"."worker_sessions", observation
WHERE status = 'online'
AND available_slots > 0
AND lease_expires_at_ms > observation.observed_at_ms
AND ($1::varchar IS NULL OR worker_id > $1)
ORDER BY worker_id
LIMIT $2
)
SELECT observation.observed_at_ms AS "observedAtMs", available.*
FROM observation LEFT JOIN available ON TRUE
ORDER BY available."workerId"
`,
[options.afterWorkerId ?? null, limit + 1],
);
if (result.rows.length < 1 || result.rows.length > limit + 1) {
throw new TypeError('PostgreSQL Worker page violated its bound');
}
const observed = integer(result.rows[0]!, 'observedAtMs');
const workers = result.rows[0]!.workerId === null
? []
: result.rows.map((row) => record(row));
const page = workers.slice(0, limit);
const last = page.at(-1);
return Object.freeze({
observedAtMs: observed,
workers: Object.freeze(page),
truncated: workers.length > limit,
...(workers.length > limit && last ? { nextCursor: last.workerId } : {}),
});
}
private async mutate<T>(
workerId: string,
work: (
client: PostgresClient,
nowMs: number,
current: WorkerSessionRecord | null,
) => Promise<T>,
): Promise<T> {
const client = await this.pool.connect();
try {
await begin(client);
const currentResult = await client.query<Row>(
`SELECT ${SELECT_COLUMNS} FROM "ql3"."worker_sessions" WHERE worker_id = $1 FOR UPDATE`,
[workerId],
);
const nowMs = await observedAtMs(client);
const result = await work(
client,
nowMs,
currentResult.rows[0] ? record(currentResult.rows[0]) : null,
);
await client.query('COMMIT');
return result;
} catch (error) {
try {
await client.query('ROLLBACK');
} catch {
// Preserve the originating failure.
}
throw error;
} finally {
client.release();
}
}
}