Add failover channel events to activity journal
Build and Deploy Gateway / build-and-push (push) Successful in 24s
Build and Deploy Gateway / deploy (push) Successful in 7s

This commit is contained in:
2026-08-27 14:36:08 +03:00
parent 4a566e082a
commit 8f2f418569
11 changed files with 388 additions and 77 deletions
@@ -128,6 +128,53 @@ test('journal exposes a latched write failure until a later append succeeds', (t
assert.equal(service.page().storage.status, 'ready');
});
test('schema version 1 keeps legacy recovery and accepts per-channel health events', (t) => {
const filePath = fixture(t);
const occurredAt = '2026-08-19T09:00:00.000Z';
fs.writeFileSync(filePath, JSON.stringify({
schemaVersion: 1,
events: [{
id: '00000000-0000-4000-8000-000000000001',
occurredAt,
type: 'failover.recovered',
severity: 'info',
source: 'failover',
dedupeKey: null,
data: { role: 'primary', reason: 'primary-recovered' },
}],
}));
let clock = new Date('2026-08-19T10:00:00.000Z');
const service = createActivityJournalService({ filePath, now: () => clock });
const inputs = [
['failover.primary_unavailable', 'primary', 'warning', 'probe-failed'],
['failover.primary_recovered', 'primary', 'info', 'probe-recovered'],
['failover.reserve_unavailable', 'reserve', 'warning', 'probe-failed'],
['failover.reserve_recovered', 'reserve', 'info', 'probe-recovered'],
];
for (const [type, role, severity, reason] of inputs) {
service.append({
type,
severity,
source: 'failover',
dedupeKey: null,
data: { role, reason },
});
clock = new Date(clock.getTime() + 1_000);
}
const page = service.page();
assert.deepEqual(page.events.map(({ type }) => type), [
'failover.reserve_recovered',
'failover.reserve_unavailable',
'failover.primary_recovered',
'failover.primary_unavailable',
'failover.recovered',
]);
assert.deepEqual(page.events.at(-1).data, { role: 'primary', reason: 'primary-recovered' });
assert.equal(page.retentionDays, 30);
assert.equal(JSON.parse(fs.readFileSync(filePath, 'utf8')).schemaVersion, 1);
});
test('journal page parser rejects malformed wire data and strips unknown event fields', (t) => {
const service = createActivityJournalService({ filePath: fixture(t) });
service.append(event('wire'));