Skip to content

Commit 0a4415b

Browse files
authored
🤖 fix: optimize git status polling with subscriber filtering (#705)
_Generated with `mux`_ ## Problem Git status polling was polling all workspaces regardless of visibility, causing performance issues. ## Solution - Optimized polling loop to only query workspaces with active subscribers (visible in sidebar) - Added unit tests for subscriber filtering logic
1 parent 6eaa7b6 commit 0a4415b

File tree

3 files changed

+53
-2
lines changed

3 files changed

+53
-2
lines changed

src/browser/stores/GitStatusStore.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,4 +388,39 @@ describe("GitStatusStore", () => {
388388
unsub();
389389
});
390390
});
391+
392+
test("skips polling when no subscribers", async () => {
393+
const metadata = {
394+
id: "ws1",
395+
name: "main",
396+
projectName: "test-project",
397+
projectPath: "/path",
398+
namedWorkspacePath: "/path",
399+
runtimeConfig: DEFAULT_RUNTIME_CONFIG,
400+
};
401+
402+
store.syncWorkspaces(new Map([["ws1", metadata]]));
403+
404+
// Ensure executeBash is cleared
405+
mockExecuteBash.mockClear();
406+
407+
// Trigger update
408+
// @ts-expect-error - Accessing private method
409+
await store.updateGitStatus();
410+
411+
// Should not have called executeBash because no subscribers
412+
expect(mockExecuteBash).not.toHaveBeenCalled();
413+
414+
// Add a subscriber
415+
const unsub = store.subscribeKey("ws1", jest.fn());
416+
417+
// Trigger update again
418+
// @ts-expect-error - Accessing private method
419+
await store.updateGitStatus();
420+
421+
// Should have called executeBash
422+
expect(mockExecuteBash).toHaveBeenCalled();
423+
424+
unsub();
425+
});
391426
});

src/browser/stores/GitStatusStore.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,21 @@ export class GitStatusStore {
146146
return;
147147
}
148148

149+
// Only poll workspaces that have active subscribers
150+
const workspaces = Array.from(this.workspaceMetadata.values()).filter((ws) =>
151+
this.statuses.hasKeySubscribers(ws.id)
152+
);
153+
154+
if (workspaces.length === 0) {
155+
return;
156+
}
157+
149158
// Try to fetch workspaces that need it (background, non-blocking)
150-
this.tryFetchWorkspaces(this.workspaceMetadata);
159+
const workspacesMap = new Map(workspaces.map((ws) => [ws.id, ws]));
160+
this.tryFetchWorkspaces(workspacesMap);
151161

152162
// Query git status for each workspace
153163
// Rate limit: Process in batches to prevent bash process explosion
154-
const workspaces = Array.from(this.workspaceMetadata.values());
155164
const results: Array<[string, GitStatus | null]> = [];
156165

157166
for (let i = 0; i < workspaces.length; i += MAX_CONCURRENT_GIT_OPS) {

src/browser/stores/MapStore.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,13 @@ export class MapStore<K, V> {
190190
};
191191
}
192192

193+
/**
194+
* Check if there are subscribers for a specific key.
195+
*/
196+
hasKeySubscribers(key: K): boolean {
197+
return this.perKey.has(key);
198+
}
199+
193200
private makeCacheKey(key: K, version: number): string {
194201
return `${String(key)}:${version}`;
195202
}

0 commit comments

Comments
 (0)