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,202 @@
require('ts-node/register/transpile-only');
const assert = require('node:assert/strict');
const { test } = require('node:test');
const {
PrimaryCancellationLifecycle,
} = require('../../back/runtime/application/primaryCancellationLifecycle');
function deferred() {
let resolve;
let reject;
const promise = new Promise((resolvePromise, rejectPromise) => {
resolve = resolvePromise;
reject = rejectPromise;
});
return { promise, resolve, reject };
}
function fakeScheduler() {
let id = 0;
const pending = new Map();
const cleared = [];
return {
pending,
cleared,
scheduler: {
setTimeout(callback, delayMs) {
const timer = {
id: ++id,
delayMs,
unrefCalls: 0,
unref() {
this.unrefCalls += 1;
},
};
pending.set(timer.id, { timer, callback });
return timer;
},
clearTimeout(timer) {
cleared.push(timer.id);
pending.delete(timer.id);
},
},
fireNext() {
const next = pending.values().next().value;
assert.ok(next, 'expected a scheduled timer');
pending.delete(next.timer.id);
next.callback();
return next.timer;
},
};
}
function cycleSummary() {
return {
pages: 1,
scanned: 1,
claimed: 1,
terminationRequested: 1,
alreadyExited: 0,
pending: 0,
ambiguous: 0,
blocked: 0,
deferred: 0,
alreadyResolved: 0,
notEligible: 0,
failed: 0,
stopReason: 'complete',
remaining: false,
};
}
async function flush() {
await new Promise((resolve) => setImmediate(resolve));
}
test('is inert until started and never overlaps slow cycles', async () => {
const timers = fakeScheduler();
const first = deferred();
let calls = 0;
const lifecycle = new PrimaryCancellationLifecycle(
{
async runCycle(options) {
calls += 1;
assert.deepEqual(options, { pageSize: 8, maxPages: 2 });
return first.promise;
},
},
{
intervalMs: 2_000,
initialDelayMs: 50,
cycle: { pageSize: 8, maxPages: 2 },
scheduler: timers.scheduler,
},
);
assert.equal(timers.pending.size, 0);
assert.equal(lifecycle.start(), true);
assert.equal(lifecycle.start(), false);
assert.equal(timers.pending.size, 1);
const initial = timers.fireNext();
assert.equal(initial.delayMs, 50);
assert.equal(initial.unrefCalls, 1);
await flush();
assert.equal(calls, 1);
assert.equal(timers.pending.size, 0);
first.resolve(cycleSummary());
await flush();
assert.equal(timers.pending.size, 1);
const next = timers.pending.values().next().value.timer;
assert.equal(next.delayMs, 2_000);
assert.equal(next.unrefCalls, 1);
assert.equal(await lifecycle.stop(), 'drained');
assert.deepEqual(timers.cleared, [next.id]);
});
test('reports cycle errors and continues without callback failure loops', async () => {
const timers = fakeScheduler();
const errors = [];
let calls = 0;
const lifecycle = new PrimaryCancellationLifecycle(
{
async runCycle() {
calls += 1;
if (calls === 1) throw new Error('database busy');
return cycleSummary();
},
},
{
intervalMs: 500,
scheduler: timers.scheduler,
onCycle() {
throw new Error('metrics sink failed');
},
onError(error) {
errors.push(error.message);
},
},
);
lifecycle.start();
timers.fireNext();
await flush();
assert.deepEqual(errors, ['database busy']);
assert.equal(timers.pending.size, 1);
timers.fireNext();
await flush();
assert.deepEqual(errors, ['database busy', 'metrics sink failed']);
assert.equal(timers.pending.size, 1);
assert.equal(await lifecycle.stop(), 'drained');
});
test('stops scheduling immediately and bounds waiting for an in-flight cycle', async () => {
const timers = fakeScheduler();
const running = deferred();
const lifecycle = new PrimaryCancellationLifecycle(
{
async runCycle() {
return running.promise;
},
},
{
intervalMs: 500,
stopTimeoutMs: 5,
scheduler: timers.scheduler,
},
);
lifecycle.start();
timers.fireNext();
await flush();
assert.equal(await lifecycle.stop(), 'timed_out');
assert.equal(timers.pending.size, 0);
assert.equal(lifecycle.start(), false);
running.resolve(cycleSummary());
await flush();
assert.equal(timers.pending.size, 0);
assert.equal(lifecycle.start(), true);
assert.equal(await lifecycle.stop(), 'drained');
});
test('rejects cadences that could create hot loops or unbounded shutdown waits', () => {
const supervisor = {
async runCycle() {
return cycleSummary();
},
};
assert.throws(
() => new PrimaryCancellationLifecycle(supervisor, { intervalMs: 249 }),
RangeError,
);
assert.throws(
() =>
new PrimaryCancellationLifecycle(supervisor, {
intervalMs: 500,
stopTimeoutMs: 60_001,
}),
RangeError,
);
});