mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 18:08:20 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const { test } = require('node:test');
|
||||
const {
|
||||
ClusterRunCancellationConvergenceUnavailableError,
|
||||
} = require('@qinglong/runtime-core/cluster-run-cancellation-convergence');
|
||||
const {
|
||||
PostgresClusterRunCancellationConvergenceRepository,
|
||||
} = require('../dist/entrypoints/runtime');
|
||||
|
||||
function row(overrides = {}) {
|
||||
return {
|
||||
observedAtMs: '1750000000100',
|
||||
runId: 'run-1',
|
||||
runStatus: 'queued',
|
||||
runVersion: 3,
|
||||
eventSequence: 4,
|
||||
runCreatedAtMs: '1750000000000',
|
||||
runQueuedAtMs: '1750000000010',
|
||||
runStartedAtMs: null,
|
||||
cancelRequestedAtMs: '1750000000050',
|
||||
cancelReason: 'user',
|
||||
attemptId: 'attempt-1',
|
||||
attemptStatus: 'claimed',
|
||||
stepRunId: null,
|
||||
attemptNumber: 1,
|
||||
attemptCreatedAtMs: '1750000000010',
|
||||
attemptStartedAtMs: null,
|
||||
attemptFinishedAtMs: null,
|
||||
leaseStatus: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function fixture(options = {}) {
|
||||
const calls = [];
|
||||
let runUpdates = 0;
|
||||
const client = {
|
||||
async query(sql, params = []) {
|
||||
const normalized = sql.replace(/\s+/g, ' ').trim();
|
||||
calls.push({ sql: normalized, params });
|
||||
if (
|
||||
normalized === 'BEGIN' || normalized === 'COMMIT' ||
|
||||
normalized === 'ROLLBACK' || normalized.startsWith('SELECT set_config')
|
||||
) return { rows: [], rowCount: 0 };
|
||||
if (normalized.startsWith('WITH observation AS MATERIALIZED')) {
|
||||
return { rows: options.rows ?? [row()], rowCount: options.rows?.length ?? 1 };
|
||||
}
|
||||
if (normalized.startsWith('UPDATE "ql3"."run_attempts"')) {
|
||||
return { rows: [], rowCount: options.attemptRowCount ?? 1 };
|
||||
}
|
||||
if (normalized.startsWith('UPDATE "ql3"."runs"')) {
|
||||
runUpdates += 1;
|
||||
return {
|
||||
rows: [],
|
||||
rowCount: options.failRunUpdate === runUpdates ? 0 : 1,
|
||||
};
|
||||
}
|
||||
if (normalized.startsWith('INSERT INTO "ql3"."run_events"')) {
|
||||
return { rows: [], rowCount: 1 };
|
||||
}
|
||||
if (normalized.startsWith('SELECT id AS "runId" FROM "ql3"."runs"')) {
|
||||
return {
|
||||
rows: options.workflowRows ?? [],
|
||||
rowCount: options.workflowRows?.length ?? 0,
|
||||
};
|
||||
}
|
||||
if (normalized.startsWith('SELECT EXISTS')) {
|
||||
return { rows: [{ hasMore: options.hasMore ?? false }], rowCount: 1 };
|
||||
}
|
||||
throw new Error(`Unexpected SQL: ${normalized}`);
|
||||
},
|
||||
release() { calls.push({ sql: 'RELEASE', params: [] }); },
|
||||
};
|
||||
return {
|
||||
repository: new PostgresClusterRunCancellationConvergenceRepository({
|
||||
async connect() { return client; },
|
||||
}),
|
||||
calls,
|
||||
};
|
||||
}
|
||||
|
||||
test('atomically settles queued claimed and lost terminal-attempt Runs', async () => {
|
||||
const { repository, calls } = fixture({
|
||||
rows: [
|
||||
row(),
|
||||
row({
|
||||
runId: 'run-2',
|
||||
runStatus: 'lost',
|
||||
runVersion: 7,
|
||||
eventSequence: 8,
|
||||
cancelReason: 'policy',
|
||||
attemptId: 'attempt-2',
|
||||
attemptStatus: 'lost',
|
||||
attemptFinishedAtMs: '1750000000020',
|
||||
}),
|
||||
],
|
||||
});
|
||||
assert.deepEqual(await repository.convergePage({
|
||||
limit: 2,
|
||||
}), {
|
||||
scanned: 2,
|
||||
settledRuns: 2,
|
||||
settledAttempts: 1,
|
||||
blocked: 0,
|
||||
hasMore: false,
|
||||
});
|
||||
const attemptUpdate = calls.find(({ sql }) =>
|
||||
sql.startsWith('UPDATE "ql3"."run_attempts"'));
|
||||
assert.equal(attemptUpdate.params[1], 'cancelled');
|
||||
const runUpdates = calls.filter(({ sql }) =>
|
||||
sql.startsWith('UPDATE "ql3"."runs"'));
|
||||
assert.equal(runUpdates.length, 2);
|
||||
assert.equal(runUpdates[0].params[5], 5);
|
||||
assert.equal(runUpdates[0].params[6], 6);
|
||||
assert.equal(runUpdates[1].params[5], 8);
|
||||
assert.equal(runUpdates[1].params[6], 9);
|
||||
const events = calls.filter(({ sql }) =>
|
||||
sql.startsWith('INSERT INTO "ql3"."run_events"'));
|
||||
assert.equal(events.length, 3);
|
||||
assert.match(events[0].params[0], /^qca-[0-9a-f]{32}$/);
|
||||
assert.match(events[1].params[0], /^qcr-[0-9a-f]{32}$/);
|
||||
assert.match(events[2].params[0], /^qcr-[0-9a-f]{32}$/);
|
||||
assert.equal(new Set(events.map(({ params }) => params[0])).size, 3);
|
||||
const candidate = calls.find(({ sql }) =>
|
||||
sql.startsWith('WITH observation AS MATERIALIZED'));
|
||||
assert.match(
|
||||
candidate.sql,
|
||||
/run\.trigger_type <> 'plugin_package_workflow'/,
|
||||
);
|
||||
assert.equal(calls.some(({ sql }) => sql === 'COMMIT'), true);
|
||||
});
|
||||
|
||||
test('maps timeout intent to timed_out and preserves database-scale time', async () => {
|
||||
const { repository, calls } = fixture({
|
||||
rows: [row({
|
||||
attemptId: null,
|
||||
attemptStatus: null,
|
||||
attemptNumber: null,
|
||||
attemptCreatedAtMs: null,
|
||||
cancelReason: 'timeout',
|
||||
})],
|
||||
});
|
||||
assert.equal((await repository.convergePage({
|
||||
limit: 1,
|
||||
})).settledRuns, 1);
|
||||
const update = calls.find(({ sql }) => sql.startsWith('UPDATE "ql3"."runs"'));
|
||||
assert.equal(update.params[1], 'timed_out');
|
||||
assert.equal(update.params[2], 1_750_000_000_100);
|
||||
assert.equal(update.params[3], 'EXECUTION_TIMED_OUT');
|
||||
});
|
||||
|
||||
test('does not forge a terminal state for an execution that crossed start', async () => {
|
||||
const { repository, calls } = fixture({
|
||||
rows: [row({
|
||||
runStatus: 'waiting_approval',
|
||||
attemptStatus: 'running',
|
||||
leaseStatus: 'leased',
|
||||
})],
|
||||
hasMore: true,
|
||||
});
|
||||
assert.deepEqual(await repository.convergePage({
|
||||
limit: 1,
|
||||
}), {
|
||||
scanned: 1,
|
||||
settledRuns: 0,
|
||||
settledAttempts: 0,
|
||||
blocked: 1,
|
||||
hasMore: true,
|
||||
});
|
||||
assert.equal(calls.some(({ sql }) => sql.startsWith('UPDATE')), false);
|
||||
});
|
||||
|
||||
test('rolls back the whole page when a Run fence changes', async () => {
|
||||
const { repository, calls } = fixture({ failRunUpdate: 1 });
|
||||
await assert.rejects(
|
||||
repository.convergePage({ limit: 1 }),
|
||||
ClusterRunCancellationConvergenceUnavailableError,
|
||||
);
|
||||
assert.equal(calls.some(({ sql }) => sql === 'ROLLBACK'), true);
|
||||
assert.equal(calls.some(({ sql }) => sql === 'COMMIT'), false);
|
||||
});
|
||||
Reference in New Issue
Block a user