perf(team): skip data refresh for log activity pulses

This commit is contained in:
777genius 2026-05-06 23:30:51 +03:00
parent b7fa5443fd
commit abe26ddcc4
2 changed files with 61 additions and 15 deletions

View file

@ -581,15 +581,19 @@ export function initializeNotificationListeners(): () => void {
};
const markTaskLogActivity = (teamName: string, taskId: string): void => {
clearTaskLogActivityTimer(teamName, taskId);
useStore.setState((prev) => ({
activeTaskLogActivityByTeam: {
...prev.activeTaskLogActivityByTeam,
[teamName]: {
...(prev.activeTaskLogActivityByTeam[teamName] ?? {}),
[taskId]: true,
const isAlreadyActive =
useStore.getState().activeTaskLogActivityByTeam[teamName]?.[taskId] === true;
if (!isAlreadyActive) {
useStore.setState((prev) => ({
activeTaskLogActivityByTeam: {
...prev.activeTaskLogActivityByTeam,
[teamName]: {
...(prev.activeTaskLogActivityByTeam[teamName] ?? {}),
[taskId]: true,
},
},
},
}));
}));
}
const timerKey = buildTaskLogActivityTimerKey(teamName, taskId);
const timer = setTimeout(() => {
taskLogActivityTimers.delete(timerKey);
@ -1703,9 +1707,13 @@ export function initializeNotificationListeners(): () => void {
seedCurrentRunIdIfMissing();
const visible = isTeamVisibleInAnyPane(event.teamName);
if (event.taskId && visible) {
if (isTaskLogActivityChangeEvent(event)) {
const isLogActivitySignal = isTaskLogActivityChangeEvent(event);
if (isLogActivitySignal) {
markTaskLogActivity(event.teamName, event.taskId);
}
if (event.taskSignalKind === 'log') {
return;
}
const existingDetailTimer = teamRefreshTimers.get(event.teamName);
noteTeamRefreshFanout({
teamName: event.teamName,

View file

@ -1623,7 +1623,7 @@ describe('team change throttling', () => {
expect(useStore.getState().activeTaskLogActivityByTeam['my-team']).toBeUndefined();
});
it('schedules a bounded team data refresh for visible task log signals', async () => {
it('pulses visible task log activity without refreshing team data for explicit log signals', async () => {
const state = useStore.getState();
const refreshTeamDataSpy = vi.spyOn(state, 'refreshTeamData');
@ -1638,11 +1638,13 @@ describe('team change throttling', () => {
);
expect(refreshTeamDataSpy).not.toHaveBeenCalled();
expect(useStore.getState().activeTaskLogActivityByTeam['my-team']).toEqual({
'task-live': true,
});
await vi.advanceTimersByTimeAsync(800);
expect(refreshTeamDataSpy).toHaveBeenCalledTimes(1);
expect(refreshTeamDataSpy).toHaveBeenCalledWith('my-team', { withDedup: true });
expect(refreshTeamDataSpy).not.toHaveBeenCalled();
});
it('refreshes visible team data for task change freshness without pulsing live log activity', async () => {
@ -1667,6 +1669,30 @@ describe('team change throttling', () => {
expect(refreshTeamDataSpy).toHaveBeenCalledWith('my-team', { withDedup: true });
});
it('keeps the bounded team data refresh for legacy task log change events', async () => {
const state = useStore.getState();
const refreshTeamDataSpy = vi.spyOn(state, 'refreshTeamData');
hoisted.onTeamChangeCb?.(
{},
{
type: 'task-log-change',
teamName: 'my-team',
taskId: 'task-live',
detail: 'opencode-runtime-task-event:start',
}
);
expect(useStore.getState().activeTaskLogActivityByTeam['my-team']).toEqual({
'task-live': true,
});
await vi.advanceTimersByTimeAsync(800);
expect(refreshTeamDataSpy).toHaveBeenCalledTimes(1);
expect(refreshTeamDataSpy).toHaveBeenCalledWith('my-team', { withDedup: true });
});
it('skips the bounded task log refresh if the team is hidden before execution', async () => {
const state = useStore.getState();
const refreshTeamDataSpy = vi.spyOn(state, 'refreshTeamData');
@ -1696,6 +1722,12 @@ describe('team change throttling', () => {
it('extends task log activity pulse on repeated log signals and ignores hidden teams', async () => {
const state = useStore.getState();
const refreshTeamDataSpy = vi.spyOn(state, 'refreshTeamData');
const activitySnapshots: Array<Record<string, true> | undefined> = [];
const unsubscribeActivitySnapshots = useStore.subscribe((nextState, prevState) => {
if (nextState.activeTaskLogActivityByTeam !== prevState.activeTaskLogActivityByTeam) {
activitySnapshots.push(nextState.activeTaskLogActivityByTeam['my-team']);
}
});
hoisted.onTeamChangeCb?.({}, {
type: 'task-log-change',
@ -1704,8 +1736,10 @@ describe('team change throttling', () => {
taskSignalKind: 'log',
});
expect(activitySnapshots).toEqual([{ 'task-live': true }]);
await vi.advanceTimersByTimeAsync(2000);
expect(refreshTeamDataSpy).toHaveBeenCalledTimes(1);
expect(refreshTeamDataSpy).not.toHaveBeenCalled();
hoisted.onTeamChangeCb?.({}, {
type: 'task-log-change',
@ -1714,14 +1748,17 @@ describe('team change throttling', () => {
taskSignalKind: 'log',
});
expect(activitySnapshots).toEqual([{ 'task-live': true }]);
await vi.advanceTimersByTimeAsync(2499);
expect(refreshTeamDataSpy).toHaveBeenCalledTimes(2);
expect(refreshTeamDataSpy).not.toHaveBeenCalled();
expect(useStore.getState().activeTaskLogActivityByTeam['my-team']).toEqual({
'task-live': true,
});
await vi.advanceTimersByTimeAsync(1);
expect(useStore.getState().activeTaskLogActivityByTeam['my-team']).toBeUndefined();
expect(activitySnapshots).toEqual([{ 'task-live': true }, undefined]);
useStore.setState({
paneLayout: {
@ -1740,7 +1777,8 @@ describe('team change throttling', () => {
expect(useStore.getState().activeTaskLogActivityByTeam['my-team']).toBeUndefined();
await vi.advanceTimersByTimeAsync(800);
expect(refreshTeamDataSpy).toHaveBeenCalledTimes(2);
expect(refreshTeamDataSpy).not.toHaveBeenCalled();
unsubscribeActivitySnapshots();
});
it('applies targeted tool resets without clearing sibling tools', async () => {