refactor(team): extract spawn status warning throttle

This commit is contained in:
777genius 2026-05-22 10:13:17 +03:00
parent 38b0a87d5d
commit 34902059b2
3 changed files with 116 additions and 8 deletions

View file

@ -58,6 +58,12 @@ import {
isMemberSpawnStatusesIpcBackoffActive,
recordMemberSpawnStatusesIpcRetryBackoff,
} from '../team/teamMemberSpawnStatusBackoff';
import {
clearAllMemberSpawnUiEqualLastWarns,
clearMemberSpawnUiEqualLastWarn,
hasMemberSpawnUiEqualLastWarn,
shouldLogMemberSpawnUiEqualSuppressed,
} from '../team/teamMemberSpawnUiEqualWarningThrottle';
import {
areInboxMessageArraysEquivalent,
clearTeamMessageSelectorCaches,
@ -184,7 +190,6 @@ const teamRefreshBurstDiagnostics = new Map<
string,
{ windowStartedAt: number; count: number; lastWarnAt: number }
>();
const memberSpawnUiEqualLastWarnAtByTeam = new Map<string, number>();
interface RefreshTeamDataOptions {
withDedup?: boolean;
}
@ -249,7 +254,7 @@ export function __resetTeamSliceModuleStateForTests(): void {
clearAllTeamLocalStateEpochs();
clearAllMemberSpawnStatusesIpcBackoffs();
teamRefreshBurstDiagnostics.clear();
memberSpawnUiEqualLastWarnAtByTeam.clear();
clearAllMemberSpawnUiEqualLastWarns();
resolvedMembersSelectorCache.clear();
resolvedMemberSelectorCache.clear();
clearTeamMessageSelectorCaches();
@ -282,7 +287,7 @@ function clearTeamScopedTransientState(teamName: string): void {
clearLastResolvedTeamDataRefreshAt(teamName);
clearMemberSpawnStatusesIpcBackoff(teamName);
teamRefreshBurstDiagnostics.delete(teamName);
memberSpawnUiEqualLastWarnAtByTeam.delete(teamName);
clearMemberSpawnUiEqualLastWarn(teamName);
clearTeamScopedSelectorCaches(teamName);
}
@ -668,7 +673,7 @@ export function __getTeamScopedTransientStateForTests(teamName: string): {
hasCurrentLocalStateEpoch: hasTeamLocalStateEpoch(teamName),
hasMemberSpawnStatusesIpcBackoff: hasMemberSpawnStatusesIpcBackoff(teamName),
hasTeamRefreshBurstDiagnostics: teamRefreshBurstDiagnostics.has(teamName),
hasMemberSpawnUiEqualLastWarn: memberSpawnUiEqualLastWarnAtByTeam.has(teamName),
hasMemberSpawnUiEqualLastWarn: hasMemberSpawnUiEqualLastWarn(teamName),
};
}
@ -957,12 +962,14 @@ function maybeLogMemberSpawnUiEqualSuppressed(
teamName: string,
runId: string | null | undefined
): void {
const now = Date.now();
const lastWarnAt = memberSpawnUiEqualLastWarnAtByTeam.get(teamName) ?? 0;
if (now - lastWarnAt < MEMBER_SPAWN_UI_EQUAL_WARN_THROTTLE_MS) {
if (
!shouldLogMemberSpawnUiEqualSuppressed(
teamName,
MEMBER_SPAWN_UI_EQUAL_WARN_THROTTLE_MS
)
) {
return;
}
memberSpawnUiEqualLastWarnAtByTeam.set(teamName, now);
logger.debug(
`[perf] member-spawn snapshot suppressed team=${teamName} runId=${runId ?? 'none'} reason=member-spawn-ui-equal`
);

View file

@ -0,0 +1,30 @@
const memberSpawnUiEqualLastWarnAtByTeam = new Map<string, number>();
export function getMemberSpawnUiEqualLastWarnAt(teamName: string): number | undefined {
return memberSpawnUiEqualLastWarnAtByTeam.get(teamName);
}
export function hasMemberSpawnUiEqualLastWarn(teamName: string): boolean {
return memberSpawnUiEqualLastWarnAtByTeam.has(teamName);
}
export function shouldLogMemberSpawnUiEqualSuppressed(
teamName: string,
throttleMs: number,
now = Date.now()
): boolean {
const lastWarnAt = memberSpawnUiEqualLastWarnAtByTeam.get(teamName) ?? 0;
if (now - lastWarnAt < throttleMs) {
return false;
}
memberSpawnUiEqualLastWarnAtByTeam.set(teamName, now);
return true;
}
export function clearMemberSpawnUiEqualLastWarn(teamName: string): void {
memberSpawnUiEqualLastWarnAtByTeam.delete(teamName);
}
export function clearAllMemberSpawnUiEqualLastWarns(): void {
memberSpawnUiEqualLastWarnAtByTeam.clear();
}

View file

@ -0,0 +1,71 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
clearAllMemberSpawnUiEqualLastWarns,
clearMemberSpawnUiEqualLastWarn,
getMemberSpawnUiEqualLastWarnAt,
hasMemberSpawnUiEqualLastWarn,
shouldLogMemberSpawnUiEqualSuppressed,
} from '../../../src/renderer/store/team/teamMemberSpawnUiEqualWarningThrottle';
afterEach(() => {
vi.useRealTimers();
clearAllMemberSpawnUiEqualLastWarns();
});
describe('teamMemberSpawnUiEqualWarningThrottle', () => {
it('preserves the existing zero fallback boundary for unknown teams', () => {
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 1_999)).toBe(false);
expect(hasMemberSpawnUiEqualLastWarn('my-team')).toBe(false);
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 2_000)).toBe(true);
expect(getMemberSpawnUiEqualLastWarnAt('my-team')).toBe(2_000);
});
it('throttles repeated warnings until the boundary is reached', () => {
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 10_000)).toBe(true);
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 11_999)).toBe(false);
expect(getMemberSpawnUiEqualLastWarnAt('my-team')).toBe(10_000);
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 12_000)).toBe(true);
expect(getMemberSpawnUiEqualLastWarnAt('my-team')).toBe(12_000);
});
it('tracks teams independently', () => {
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 10_000)).toBe(true);
expect(shouldLogMemberSpawnUiEqualSuppressed('other-team', 2_000, 10_500)).toBe(true);
expect(getMemberSpawnUiEqualLastWarnAt('my-team')).toBe(10_000);
expect(getMemberSpawnUiEqualLastWarnAt('other-team')).toBe(10_500);
});
it('uses Date.now by default for production callers', () => {
vi.setSystemTime(new Date('2026-05-22T07:30:00.000Z'));
expect(shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000)).toBe(true);
expect(getMemberSpawnUiEqualLastWarnAt('my-team')).toBe(
new Date('2026-05-22T07:30:00.000Z').getTime()
);
});
it('clears one team without touching other teams', () => {
shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 10_000);
shouldLogMemberSpawnUiEqualSuppressed('other-team', 2_000, 10_500);
clearMemberSpawnUiEqualLastWarn('my-team');
expect(hasMemberSpawnUiEqualLastWarn('my-team')).toBe(false);
expect(getMemberSpawnUiEqualLastWarnAt('other-team')).toBe(10_500);
});
it('clears all tracked warnings', () => {
shouldLogMemberSpawnUiEqualSuppressed('my-team', 2_000, 10_000);
shouldLogMemberSpawnUiEqualSuppressed('other-team', 2_000, 10_500);
clearAllMemberSpawnUiEqualLastWarns();
expect(hasMemberSpawnUiEqualLastWarn('my-team')).toBe(false);
expect(hasMemberSpawnUiEqualLastWarn('other-team')).toBe(false);
});
});