mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
86 lines
2.5 KiB
TypeScript
86 lines
2.5 KiB
TypeScript
import { QueryTypes, Sequelize } from 'sequelize';
|
|
import { RUN_TABLE } from '../../../migrations/0002-run-schema';
|
|
import {
|
|
RUN_LOST_RETRY_INDEX,
|
|
RUN_RETRY_POLICY_DUE_INDEX,
|
|
RUN_RETRY_POLICY_TABLE,
|
|
} from '../../../migrations/0011-run-retry-policy';
|
|
import {
|
|
MAX_RUN_LOST_RETRY_PAGE_SIZE,
|
|
type ListRunLostRetryCandidatesOptions,
|
|
type RunLostRetryCandidate,
|
|
type RunLostRetrySource,
|
|
} from '../../ports/runLostRetrySource';
|
|
|
|
interface RunLostRetryCandidateRow {
|
|
runId: string;
|
|
phase: 'lost' | 'retry_wait';
|
|
availableAtMs: number | string;
|
|
}
|
|
|
|
export class LegacySequelizeRunLostRetrySource implements RunLostRetrySource {
|
|
constructor(private readonly database: Sequelize) {
|
|
if (database.getDialect() !== 'sqlite') {
|
|
throw new TypeError(
|
|
'Legacy lost retry source is SQLite-only; cluster-control requires a PostgreSQL adapter',
|
|
);
|
|
}
|
|
}
|
|
|
|
async listCandidates({
|
|
observedAtMs,
|
|
limit = 16,
|
|
}: ListRunLostRetryCandidatesOptions): Promise<
|
|
readonly RunLostRetryCandidate[]
|
|
> {
|
|
if (!Number.isSafeInteger(observedAtMs) || observedAtMs < 0) {
|
|
throw new RangeError('observedAtMs must be a non-negative safe integer');
|
|
}
|
|
if (
|
|
!Number.isSafeInteger(limit) ||
|
|
limit < 1 ||
|
|
limit > MAX_RUN_LOST_RETRY_PAGE_SIZE
|
|
) {
|
|
throw new RangeError(
|
|
`limit must be between 1 and ${MAX_RUN_LOST_RETRY_PAGE_SIZE}`,
|
|
);
|
|
}
|
|
const rows = await this.database.query<RunLostRetryCandidateRow>(
|
|
`SELECT runId, phase, availableAtMs
|
|
FROM (
|
|
SELECT
|
|
r.id AS runId,
|
|
'lost' AS phase,
|
|
0 AS availableAtMs
|
|
FROM ${RUN_TABLE} r INDEXED BY ${RUN_LOST_RETRY_INDEX}
|
|
WHERE r.execution_owner = 'runtime'
|
|
AND r.status = 'lost'
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
r.id AS runId,
|
|
'retry_wait' AS phase,
|
|
p.next_attempt_at_ms AS availableAtMs
|
|
FROM ${RUN_RETRY_POLICY_TABLE} p INDEXED BY ${RUN_RETRY_POLICY_DUE_INDEX}
|
|
INNER JOIN ${RUN_TABLE} r ON r.id = p.run_id
|
|
WHERE p.next_attempt_at_ms IS NOT NULL
|
|
AND p.next_attempt_at_ms <= :observedAtMs
|
|
AND r.execution_owner = 'runtime'
|
|
AND r.status = 'retry_wait'
|
|
) candidates
|
|
ORDER BY availableAtMs ASC, runId ASC
|
|
LIMIT :limit`,
|
|
{
|
|
type: QueryTypes.SELECT,
|
|
replacements: { observedAtMs, limit },
|
|
},
|
|
);
|
|
return rows.map((row) => ({
|
|
runId: row.runId,
|
|
phase: row.phase,
|
|
availableAtMs: Number(row.availableAtMs),
|
|
}));
|
|
}
|
|
}
|