fix(gateway): harden heartbeat timeout recovery to avoid reconnect flapping (#588)
Co-authored-by: zuolingxuan <zuolingxuan@bytedance.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
8cca9af773
commit
8029b507ba
70
tests/unit/gateway-connection-monitor.test.ts
Normal file
70
tests/unit/gateway-connection-monitor.test.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { GatewayConnectionMonitor } from '@electron/gateway/connection-monitor';
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
app: {
|
||||
getPath: () => '/tmp',
|
||||
getVersion: () => '0.0.0-test',
|
||||
isPackaged: false,
|
||||
},
|
||||
utilityProcess: {
|
||||
fork: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('GatewayConnectionMonitor heartbeat', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date('2026-03-19T00:00:00.000Z'));
|
||||
});
|
||||
|
||||
it('terminates only after consecutive heartbeat misses reach threshold', () => {
|
||||
const monitor = new GatewayConnectionMonitor();
|
||||
const sendPing = vi.fn();
|
||||
const onHeartbeatTimeout = vi.fn();
|
||||
|
||||
monitor.startPing({
|
||||
sendPing,
|
||||
onHeartbeatTimeout,
|
||||
intervalMs: 100,
|
||||
timeoutMs: 50,
|
||||
maxConsecutiveMisses: 3,
|
||||
});
|
||||
|
||||
vi.advanceTimersByTime(100); // send ping #1
|
||||
vi.advanceTimersByTime(100); // miss #1, send ping #2
|
||||
vi.advanceTimersByTime(100); // miss #2, send ping #3
|
||||
expect(onHeartbeatTimeout).not.toHaveBeenCalled();
|
||||
|
||||
vi.advanceTimersByTime(100); // miss #3 -> timeout callback
|
||||
expect(onHeartbeatTimeout).toHaveBeenCalledTimes(1);
|
||||
expect(onHeartbeatTimeout).toHaveBeenCalledWith({ consecutiveMisses: 3, timeoutMs: 50 });
|
||||
expect(sendPing).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('resets miss counter when alive signal is received', () => {
|
||||
const monitor = new GatewayConnectionMonitor();
|
||||
const sendPing = vi.fn();
|
||||
const onHeartbeatTimeout = vi.fn();
|
||||
|
||||
monitor.startPing({
|
||||
sendPing,
|
||||
onHeartbeatTimeout,
|
||||
intervalMs: 100,
|
||||
timeoutMs: 50,
|
||||
maxConsecutiveMisses: 2,
|
||||
});
|
||||
|
||||
vi.advanceTimersByTime(100); // send ping #1
|
||||
vi.advanceTimersByTime(100); // miss #1, send ping #2
|
||||
expect(monitor.getConsecutiveMisses()).toBe(1);
|
||||
|
||||
monitor.markAlive('pong');
|
||||
expect(monitor.getConsecutiveMisses()).toBe(0);
|
||||
|
||||
vi.advanceTimersByTime(100); // send ping #3
|
||||
vi.advanceTimersByTime(100); // miss #1 again (reset confirmed)
|
||||
expect(monitor.getConsecutiveMisses()).toBe(1);
|
||||
expect(onHeartbeatTimeout).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user