feat(companion): add heartbeat loop jitter controls

This commit is contained in:
William Valentin
2026-02-16 18:57:56 -08:00
parent fd59d88c0c
commit 01b24e71b9
4 changed files with 58 additions and 2 deletions
+21
View File
@@ -42,6 +42,12 @@ describe('CompanionHeartbeatLoop', () => {
expect(() => new CompanionHeartbeatLoop(publisher, { intervalMs: 0 })).toThrow(
'intervalMs must be a positive number',
);
expect(() => new CompanionHeartbeatLoop(publisher, { jitterRatio: -0.1 })).toThrow(
'jitterRatio must be between 0 and 1',
);
expect(() => new CompanionHeartbeatLoop(publisher, { jitterRatio: 1.1 })).toThrow(
'jitterRatio must be between 0 and 1',
);
expect(() => new CompanionHeartbeatLoop(publisher, { maxConsecutiveFailures: 0 })).toThrow(
'maxConsecutiveFailures must be >= 1 when specified',
);
@@ -60,6 +66,21 @@ describe('CompanionHeartbeatLoop', () => {
loop.stop();
});
it('applies jitterRatio to scheduling delay bounds', async () => {
const publishHeartbeat = vi.fn(async () => buildStatusResult());
const loop = new CompanionHeartbeatLoop(
{ publishHeartbeat },
{ intervalMs: 1000, jitterRatio: 0.5, randomFn: () => 1 },
);
loop.start(false);
await vi.advanceTimersByTimeAsync(1499);
expect(publishHeartbeat).toHaveBeenCalledTimes(0);
await vi.advanceTimersByTimeAsync(1);
expect(publishHeartbeat).toHaveBeenCalledTimes(1);
loop.stop();
});
it('passes buildHeartbeat payload into publishHeartbeat', async () => {
const publishHeartbeat = vi.fn(async () => buildStatusResult());
const buildHeartbeat = vi.fn(() => ({ statusText: 'loop', powerSource: 'ac' as const }));