perf(main): drop localhost label routes when a worktree is removed (#7557)

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Neil 2026-07-06 16:43:05 -07:00 committed by GitHub
parent 7237c8e592
commit ec52db6d20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 45 additions and 0 deletions

View File

@ -103,6 +103,7 @@ type CreateWorktreeArgsWithSystemProvenance = CreateWorktreeArgs & {
}
import { classifyWorkspaceCreateError } from './workspace-create-error-classifier'
import { advertisedUrlWatcher } from '../ports/advertised-url-watcher'
import { localhostWorktreeLabelProxy } from '../localhost-worktree-label-proxy'
import {
assertWorktreeDoesNotContainRegisteredWorktree,
canCleanupUnregisteredOrcaLeftoverDirectory,
@ -161,6 +162,9 @@ function removeWorktreeMetadataAndTransientState(store: Store, worktreeId: strin
// drop process-local caches before the same ID can point at a new workspace.
store.removeWorktreeMeta(worktreeId)
advertisedUrlWatcher.forgetWorktree(worktreeId)
// Why: drop this worktree's localhost label routes so they don't accumulate
// in the proxy's route maps for the rest of the session.
localhostWorktreeLabelProxy.unregisterWorktree(worktreeId)
deleteWorktreeHistoryDir(worktreeId)
// Why: release the removed worktree's PR-refresh aliases so coalesced queue
// entries do not retain it for the rest of the session (memory creep).

View File

@ -124,4 +124,33 @@ describe('localhost worktree label proxy', () => {
expect(result.status).toBe(404)
})
it('drops a worktree label routes on unregisterWorktree, leaving others intact', async () => {
const port = await startUpstream((_request, response) => {
response.writeHead(200, { 'content-type': 'text/plain' })
response.end('ok')
})
const proxy = new LocalhostWorktreeLabelProxy()
const a = await proxy.registerRoute({
targetUrl: `http://localhost:${port}/`,
projectName: 'Snap Studio',
worktreeName: 'feature-a',
worktreeId: 'wt-a'
})
const b = await proxy.registerRoute({
targetUrl: `http://localhost:${port}/`,
projectName: 'Snap Studio',
worktreeName: 'feature-b',
worktreeId: 'wt-b'
})
expect((await fetchThroughProxy(a.url)).status).toBe(200)
expect((await fetchThroughProxy(b.url)).status).toBe(200)
proxy.unregisterWorktree('wt-a')
// The removed worktree's label no longer routes; the other worktree is unaffected.
expect((await fetchThroughProxy(a.url)).status).toBe(404)
expect((await fetchThroughProxy(b.url)).status).toBe(200)
})
})

View File

@ -49,6 +49,18 @@ export class LocalhostWorktreeLabelProxy {
}
}
// Why: routes are added per (worktreeId, targetUrl) but were never removed, so
// labels for deleted worktrees accumulated in both maps for the whole session.
// Drop them when the worktree is torn down. The shared http.Server stays up.
unregisterWorktree(worktreeId: string): void {
for (const [label, route] of this.routes) {
if (route.worktreeId === worktreeId) {
this.routes.delete(label)
this.routeKeys.delete(route.routeKey)
}
}
}
private async ensureServer(): Promise<void> {
if (this.server && this.listenPort !== null) {
return