mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 02:27:44 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { QueryTypes, Sequelize } from 'sequelize';
|
||||
import {
|
||||
RUN_ATTEMPT_TABLE,
|
||||
RUN_TABLE,
|
||||
} from '../../../migrations/0002-run-schema';
|
||||
import { LOCAL_ARTIFACT_RETENTION_TABLE } from '../../../migrations/0015-local-artifact-retention';
|
||||
import {
|
||||
normalizeLocalArtifactReadMetadata,
|
||||
type LocalArtifactReadMetadata,
|
||||
} from '../../domain/artifactRead';
|
||||
import type { LocalArtifactReadMetadataRepository } from '../../ports/localArtifactReadMetadataRepository';
|
||||
|
||||
interface ArtifactMetadataRow {
|
||||
project_id: string;
|
||||
run_id: string;
|
||||
attempt_id: string;
|
||||
attempt_finished_at_ms: number | string | null;
|
||||
log_artifact_id: string;
|
||||
retention_log_artifact_id: string | null;
|
||||
retention_disposition: string | null;
|
||||
retention_finished_at_ms: number | string | null;
|
||||
retention_eligible_at_ms: number | string | null;
|
||||
retention_bytes_reclaimed: number | string | null;
|
||||
retention_recorded_at_ms: number | string | null;
|
||||
}
|
||||
|
||||
export class CorruptLocalArtifactReadMetadataError extends Error {
|
||||
constructor() {
|
||||
super('Local Artifact read metadata is corrupt or ambiguous');
|
||||
this.name = 'CorruptLocalArtifactReadMetadataError';
|
||||
}
|
||||
}
|
||||
|
||||
function rowToMetadata(
|
||||
row: ArtifactMetadataRow,
|
||||
): Readonly<LocalArtifactReadMetadata> {
|
||||
const retentionValues = [
|
||||
row.retention_log_artifact_id,
|
||||
row.retention_disposition,
|
||||
row.retention_finished_at_ms,
|
||||
row.retention_eligible_at_ms,
|
||||
row.retention_bytes_reclaimed,
|
||||
row.retention_recorded_at_ms,
|
||||
];
|
||||
const hasRetention = retentionValues.every((value) => value !== null);
|
||||
if (!hasRetention && retentionValues.some((value) => value !== null)) {
|
||||
throw new CorruptLocalArtifactReadMetadataError();
|
||||
}
|
||||
if (hasRetention && row.retention_log_artifact_id !== row.log_artifact_id) {
|
||||
throw new CorruptLocalArtifactReadMetadataError();
|
||||
}
|
||||
if (
|
||||
hasRetention &&
|
||||
(row.attempt_finished_at_ms === null ||
|
||||
Number(row.retention_finished_at_ms) !==
|
||||
Number(row.attempt_finished_at_ms))
|
||||
) {
|
||||
throw new CorruptLocalArtifactReadMetadataError();
|
||||
}
|
||||
try {
|
||||
return normalizeLocalArtifactReadMetadata({
|
||||
projectId: row.project_id,
|
||||
runId: row.run_id,
|
||||
attemptId: row.attempt_id,
|
||||
logArtifactId: row.log_artifact_id,
|
||||
...(hasRetention
|
||||
? {
|
||||
retention: {
|
||||
disposition: row.retention_disposition as NonNullable<
|
||||
LocalArtifactReadMetadata['retention']
|
||||
>['disposition'],
|
||||
finishedAtMs: Number(row.retention_finished_at_ms),
|
||||
eligibleAtMs: Number(row.retention_eligible_at_ms),
|
||||
bytesReclaimed: Number(row.retention_bytes_reclaimed),
|
||||
recordedAtMs: Number(row.retention_recorded_at_ms),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof CorruptLocalArtifactReadMetadataError) throw error;
|
||||
throw new CorruptLocalArtifactReadMetadataError();
|
||||
}
|
||||
}
|
||||
|
||||
export class LegacySequelizeLocalArtifactReadMetadataRepository
|
||||
implements LocalArtifactReadMetadataRepository
|
||||
{
|
||||
constructor(private readonly database: Sequelize) {
|
||||
if (database.getDialect() !== 'sqlite') {
|
||||
throw new TypeError(
|
||||
'Local Artifact read metadata repository is SQLite-only; cluster-control requires a PostgreSQL adapter',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async find({
|
||||
projectId,
|
||||
runId,
|
||||
logArtifactId,
|
||||
}: Parameters<
|
||||
LocalArtifactReadMetadataRepository['find']
|
||||
>[0]): Promise<Readonly<LocalArtifactReadMetadata> | null> {
|
||||
const rows = await this.database.query<ArtifactMetadataRow>(
|
||||
`SELECT run.project_id,
|
||||
run.id AS run_id,
|
||||
attempt.id AS attempt_id,
|
||||
attempt.finished_at_ms AS attempt_finished_at_ms,
|
||||
attempt.log_artifact_id,
|
||||
retained.log_artifact_id AS retention_log_artifact_id,
|
||||
retained.disposition AS retention_disposition,
|
||||
retained.finished_at_ms AS retention_finished_at_ms,
|
||||
retained.eligible_at_ms AS retention_eligible_at_ms,
|
||||
retained.bytes_reclaimed AS retention_bytes_reclaimed,
|
||||
retained.recorded_at_ms AS retention_recorded_at_ms
|
||||
FROM "${RUN_TABLE}" AS run
|
||||
JOIN "${RUN_ATTEMPT_TABLE}" AS attempt ON attempt.run_id = run.id
|
||||
LEFT JOIN "${LOCAL_ARTIFACT_RETENTION_TABLE}" AS retained
|
||||
ON retained.attempt_id = attempt.id
|
||||
WHERE run.project_id = :projectId
|
||||
AND run.id = :runId
|
||||
AND run.execution_owner = 'runtime'
|
||||
AND attempt.executor_type = 'local_process'
|
||||
AND attempt.log_artifact_id = :logArtifactId
|
||||
AND attempt.log_artifact_id LIKE 'local-%'
|
||||
LIMIT 2`,
|
||||
{
|
||||
type: QueryTypes.SELECT,
|
||||
replacements: { projectId, runId, logArtifactId },
|
||||
},
|
||||
);
|
||||
if (rows.length === 0) return null;
|
||||
if (rows.length !== 1) throw new CorruptLocalArtifactReadMetadataError();
|
||||
return rowToMetadata(rows[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user