Read chat logs incrementally and drain retention (Refs #62)

This commit is contained in:
2026-10-08 17:28:49 -04:00
parent 0cc4498b53
commit c10f602e8e
18 changed files with 646 additions and 39 deletions
+26 -8
View File
@@ -6,7 +6,7 @@ vi.mock('../../src/lib/server/pipeline/beta-runner.js', () => ({ betaTick: vi.fn
vi.mock('../../src/lib/server/maintenance/index.js', () => ({ runMaintenance: vi.fn() }));
vi.mock('../../src/lib/server/game-files/index.js', () => ({ cleanupControllerLibraries: vi.fn(async () => {}) }));
vi.mock('../../src/lib/server/provisioning/worker.js', () => ({ processProvisioning: vi.fn(async () => {}) }));
vi.mock('../../src/lib/server/retention.js', () => ({ pruneHistory: vi.fn(), pruneSampleHistory: vi.fn() }));
vi.mock('../../src/lib/server/retention.js', () => ({ drainRetention: vi.fn(async () => 0) }));
vi.mock('../../src/lib/server/fleet/chat.js', () => ({ collectFleetChat: vi.fn(async () => {}) }));
function deferred() {
@@ -58,19 +58,16 @@ describe('independent provisioning scheduling', () => {
it('runs retention at most every five minutes across ticks and explicit kicks', async () => {
const s = await setup();
const { pruneHistory, pruneSampleHistory } = await import('../../src/lib/server/retention.js');
const { drainRetention } = await import('../../src/lib/server/retention.js');
vi.useFakeTimers();
try {
s.startWorker();
expect(pruneHistory).toHaveBeenCalledTimes(1);
expect(pruneSampleHistory).toHaveBeenCalledTimes(1);
expect(drainRetention).toHaveBeenCalledTimes(1);
await vi.advanceTimersByTimeAsync(285_000);
await s.kick();
expect(pruneHistory).toHaveBeenCalledTimes(1);
expect(pruneSampleHistory).toHaveBeenCalledTimes(1);
expect(drainRetention).toHaveBeenCalledTimes(1);
await vi.advanceTimersByTimeAsync(15_000);
expect(pruneHistory).toHaveBeenCalledTimes(2);
expect(pruneSampleHistory).toHaveBeenCalledTimes(2);
expect(drainRetention).toHaveBeenCalledTimes(2);
expect(s.process.mock.calls.length).toBeGreaterThan(2);
} finally {
s.stopWorker(); s.background.resolve();
@@ -80,6 +77,27 @@ describe('independent provisioning scheduling', () => {
}
});
it('keeps a retention backlog running without overlapping it or blocking provisioning', async () => {
const s = await setup();
const { drainRetention } = await import('../../src/lib/server/retention.js');
const cleanup = deferred();
vi.mocked(drainRetention).mockImplementationOnce(async () => { await cleanup.promise; return 1501; });
vi.useFakeTimers();
try {
s.startWorker();
await vi.advanceTimersByTimeAsync(600_000);
expect(drainRetention).toHaveBeenCalledTimes(1);
expect(s.process.mock.calls.length).toBeGreaterThan(2);
cleanup.resolve();
await vi.advanceTimersByTimeAsync(0);
} finally {
s.stopWorker(); cleanup.resolve(); s.background.resolve();
await vi.advanceTimersByTimeAsync(0);
vi.useRealTimers();
await vi.waitFor(() => expect(s.workerActivity()).toEqual([]));
}
});
it('runs controller library cleanup on worker ticks without overlapping a slow cleanup', async () => {
const s = await setup();
const { cleanupControllerLibraries } = await import('../../src/lib/server/game-files/index.js');