Skip to content

Commit 098bc28

Browse files
committed
refactor(agent): implement parallel resource cleanup
This change improves the resource cleanup process by handling browser sessions, shell processes, and sub-agents in parallel rather than sequentially. The implementation: 1. Refactors the cleanup method into smaller helper methods for each resource type 2. Uses Promise.all to execute cleanup operations concurrently 3. Filters tools by status during the initial grouping to simplify the code This approach significantly speeds up the cleanup process, especially when dealing with multiple resources of different types.
1 parent 576436e commit 098bc28

File tree

2 files changed

+99
-77
lines changed

2 files changed

+99
-77
lines changed

commit_message.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
feat(agent): implement incremental resource cleanup for agent lifecycle
1+
refactor(agent): implement parallel resource cleanup
22

3-
This commit adds a new cleanup method to the BackgroundTools class that handles
4-
cleaning up browser sessions, shell processes, and sub-agents associated with an
5-
agent when it completes its task, encounters an error, or is terminated.
3+
This change improves the resource cleanup process by handling browser sessions,
4+
shell processes, and sub-agents in parallel rather than sequentially.
65

7-
The changes include:
6+
The implementation:
7+
1. Refactors the cleanup method into smaller helper methods for each resource type
8+
2. Uses Promise.all to execute cleanup operations concurrently
9+
3. Filters tools by status during the initial grouping to simplify the code
810

9-
- Adding a cleanup method to BackgroundTools that cleans up resources
10-
- Calling cleanup when agents complete successfully
11-
- Calling cleanup when agents encounter errors
12-
- Calling cleanup when agents are terminated
13-
- Enhancing global cleanup to first attempt to clean up any still-running agents
14-
- Adding tests for the new cleanup functionality
15-
16-
Fixes #236
11+
This approach significantly speeds up the cleanup process, especially when
12+
dealing with multiple resources of different types.

packages/agent/src/core/backgroundTools.ts

Lines changed: 90 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -173,89 +173,115 @@ export class BackgroundTools {
173173
// Group tools by type for better cleanup organization
174174
const browserTools = tools.filter(
175175
(tool): tool is BrowserBackgroundTool =>
176-
tool.type === BackgroundToolType.BROWSER,
176+
tool.type === BackgroundToolType.BROWSER &&
177+
tool.status === BackgroundToolStatus.RUNNING,
177178
);
178179

179180
const shellTools = tools.filter(
180181
(tool): tool is ShellBackgroundTool =>
181-
tool.type === BackgroundToolType.SHELL,
182+
tool.type === BackgroundToolType.SHELL &&
183+
tool.status === BackgroundToolStatus.RUNNING,
182184
);
183185

184186
const agentTools = tools.filter(
185187
(tool): tool is AgentBackgroundTool =>
186-
tool.type === BackgroundToolType.AGENT,
188+
tool.type === BackgroundToolType.AGENT &&
189+
tool.status === BackgroundToolStatus.RUNNING,
187190
);
188191

189-
// Clean up browser sessions
190-
for (const tool of browserTools) {
191-
if (tool.status === BackgroundToolStatus.RUNNING) {
192-
try {
193-
const browserManager = (
194-
globalThis as unknown as { __BROWSER_MANAGER__?: BrowserManager }
195-
).__BROWSER_MANAGER__;
196-
if (browserManager) {
197-
await browserManager.closeSession(tool.id);
198-
}
199-
this.updateToolStatus(tool.id, BackgroundToolStatus.COMPLETED);
200-
} catch (error) {
201-
this.updateToolStatus(tool.id, BackgroundToolStatus.ERROR, {
202-
error: error instanceof Error ? error.message : String(error),
203-
});
204-
}
192+
// Create cleanup promises for each resource type
193+
const browserCleanupPromises = browserTools.map((tool) =>
194+
this.cleanupBrowserSession(tool),
195+
);
196+
const shellCleanupPromises = shellTools.map((tool) =>
197+
this.cleanupShellProcess(tool),
198+
);
199+
const agentCleanupPromises = agentTools.map((tool) =>
200+
this.cleanupSubAgent(tool),
201+
);
202+
203+
// Wait for all cleanup operations to complete in parallel
204+
await Promise.all([
205+
...browserCleanupPromises,
206+
...shellCleanupPromises,
207+
...agentCleanupPromises,
208+
]);
209+
}
210+
211+
/**
212+
* Cleans up a browser session
213+
* @param tool The browser tool to clean up
214+
*/
215+
private async cleanupBrowserSession(
216+
tool: BrowserBackgroundTool,
217+
): Promise<void> {
218+
try {
219+
const browserManager = (
220+
globalThis as unknown as { __BROWSER_MANAGER__?: BrowserManager }
221+
).__BROWSER_MANAGER__;
222+
if (browserManager) {
223+
await browserManager.closeSession(tool.id);
205224
}
225+
this.updateToolStatus(tool.id, BackgroundToolStatus.COMPLETED);
226+
} catch (error) {
227+
this.updateToolStatus(tool.id, BackgroundToolStatus.ERROR, {
228+
error: error instanceof Error ? error.message : String(error),
229+
});
206230
}
231+
}
207232

208-
// Clean up shell processes
209-
for (const tool of shellTools) {
210-
if (tool.status === BackgroundToolStatus.RUNNING) {
211-
try {
212-
const processState = processStates.get(tool.id);
213-
if (processState && !processState.state.completed) {
214-
processState.process.kill('SIGTERM');
233+
/**
234+
* Cleans up a shell process
235+
* @param tool The shell tool to clean up
236+
*/
237+
private async cleanupShellProcess(tool: ShellBackgroundTool): Promise<void> {
238+
try {
239+
const processState = processStates.get(tool.id);
240+
if (processState && !processState.state.completed) {
241+
processState.process.kill('SIGTERM');
215242

216-
// Force kill after a short timeout if still running
217-
await new Promise<void>((resolve) => {
218-
setTimeout(() => {
219-
try {
220-
if (!processState.state.completed) {
221-
processState.process.kill('SIGKILL');
222-
}
223-
} catch {
224-
// Ignore errors on forced kill
225-
}
226-
resolve();
227-
}, 500);
228-
});
229-
}
230-
this.updateToolStatus(tool.id, BackgroundToolStatus.COMPLETED);
231-
} catch (error) {
232-
this.updateToolStatus(tool.id, BackgroundToolStatus.ERROR, {
233-
error: error instanceof Error ? error.message : String(error),
234-
});
235-
}
243+
// Force kill after a short timeout if still running
244+
await new Promise<void>((resolve) => {
245+
setTimeout(() => {
246+
try {
247+
if (!processState.state.completed) {
248+
processState.process.kill('SIGKILL');
249+
}
250+
} catch {
251+
// Ignore errors on forced kill
252+
}
253+
resolve();
254+
}, 500);
255+
});
236256
}
257+
this.updateToolStatus(tool.id, BackgroundToolStatus.COMPLETED);
258+
} catch (error) {
259+
this.updateToolStatus(tool.id, BackgroundToolStatus.ERROR, {
260+
error: error instanceof Error ? error.message : String(error),
261+
});
237262
}
263+
}
238264

239-
// Clean up sub-agents
240-
for (const tool of agentTools) {
241-
if (tool.status === BackgroundToolStatus.RUNNING) {
242-
try {
243-
const agentState = agentStates.get(tool.id);
244-
if (agentState && !agentState.aborted) {
245-
// Set the agent as aborted and completed
246-
agentState.aborted = true;
247-
agentState.completed = true;
265+
/**
266+
* Cleans up a sub-agent
267+
* @param tool The agent tool to clean up
268+
*/
269+
private async cleanupSubAgent(tool: AgentBackgroundTool): Promise<void> {
270+
try {
271+
const agentState = agentStates.get(tool.id);
272+
if (agentState && !agentState.aborted) {
273+
// Set the agent as aborted and completed
274+
agentState.aborted = true;
275+
agentState.completed = true;
248276

249-
// Clean up resources owned by this sub-agent
250-
await agentState.context.backgroundTools.cleanup();
251-
}
252-
this.updateToolStatus(tool.id, BackgroundToolStatus.TERMINATED);
253-
} catch (error) {
254-
this.updateToolStatus(tool.id, BackgroundToolStatus.ERROR, {
255-
error: error instanceof Error ? error.message : String(error),
256-
});
257-
}
277+
// Clean up resources owned by this sub-agent
278+
await agentState.context.backgroundTools.cleanup();
258279
}
280+
this.updateToolStatus(tool.id, BackgroundToolStatus.TERMINATED);
281+
} catch (error) {
282+
this.updateToolStatus(tool.id, BackgroundToolStatus.ERROR, {
283+
error: error instanceof Error ? error.message : String(error),
284+
});
259285
}
260286
}
261287
}

0 commit comments

Comments
 (0)