fix(worker): always release stopped workspaces

This commit is contained in:
Gabriel Brown
2026-07-10 17:35:33 -04:00
parent 00f96a126e
commit 8af33fc9e0
2 changed files with 222 additions and 8 deletions
+35 -8
View File
@@ -139,6 +139,13 @@ const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
const client = new ConvexHttpClient(env.convexUrl);
const activeWorkspaces = new Map<string, ActiveWorkspace>();
export const _setActiveWorkspaceForTests = (
jobId: string,
workspace: ActiveWorkspace,
) => activeWorkspaces.set(jobId, workspace);
export const _resetActiveWorkspacesForTests = () => activeWorkspaces.clear();
const appendEvent = async (
jobId: Id<'agentJobs'>,
level: 'debug' | 'info' | 'warn' | 'error',
@@ -1894,15 +1901,35 @@ export const openWorkspacePullRequest = async (jobId: string) => {
export const stopWorkspace = async (jobId: string) => {
const workspace = resolveWorkspace(jobId);
await markWorkspaceStopped(workspace.claim.job._id);
workspace.opencodeSession?.close();
if (workspace.containerName) {
await stopWorkspaceContainer(workspace.containerName);
const errors: unknown[] = [];
try {
await markWorkspaceStopped(workspace.claim.job._id);
} catch (error) {
errors.push(error);
}
try {
workspace.opencodeSession?.close();
} catch (error) {
errors.push(error);
}
try {
if (workspace.containerName) {
await stopWorkspaceContainer(workspace.containerName);
}
} catch (error) {
errors.push(error);
} finally {
activeWorkspaces.delete(jobId);
try {
workspace.boxHandle.release();
} catch (error) {
errors.push(error);
}
}
if (errors.length === 1) throw errors[0];
if (errors.length > 1) {
throw new AggregateError(errors, 'Workspace teardown failed.');
}
activeWorkspaces.delete(jobId);
// The persistent per-user home + ~/Code checkouts survive across sessions;
// release the box (reaped once no other thread/terminal holds it).
workspace.boxHandle.release();
return { success: true };
};