-
Notifications
You must be signed in to change notification settings - Fork 8
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Issue: Agent Sessions Not Cleaned Up When Tasks Are Deleted
Problem
Resource Leak: When a user deletes a task, the associated agent session remains active, causing:
- Cloud sessions: Polling continues forever fetching from deleted task's S3 URLs
- Local sessions: tRPC subscriptions stay active, agent processes keep running
- Memory leaks: Session objects accumulate in session store
- Performance degradation over time
Root Cause
Missing cleanup in task deletion flow:
// Current flow in useDeleteTask() - BROKEN
return client.deleteTask(taskId); // ✅ Deletes task
// ❌ MISSING: Clean up associated sessionsTasks and sessions have 1-to-many relationship but only 1-way cleanup.
Fix Location
File: apps/twig/src/renderer/features/tasks/hooks/useTasks.ts
Function: useDeleteTask() → mutation.onMutate
Exact Fix
Add session cleanup in the onMutate callback:
export function useDeleteTask() {
const queryClient = useQueryClient();
const { view, navigateToTaskInput } = useNavigationStore();
const unpinTask = usePinnedTasksStore((state) => state.unpin);
const sessions = useSessions(); // ✅ Hook at top level
const sessionActions = useSessionActions(); // ✅ Hook at top level
const mutation = useAuthenticatedMutation(
async (client, taskId: string) => {
// ... existing workspace cleanup ...
return client.deleteTask(taskId);
},
{
onMutate: async (taskId) => {
// ✅ NEW: Clean up session resources when task is deleted
const activeSession = Object.values(sessions).find((s) => s.taskId === taskId);
if (activeSession) {
log.info("Cleaning up session during task deletion", {
taskRunId: activeSession.taskRunId,
taskId
});
// ✅ This handles both cloud and local sessions
await sessionActions.disconnectFromTask(taskId);
}
// ... existing optimistic update logic ...
},
},
);
}Why This Fix Works
-
disconnectFromTask()properly handles:- Cloud sessions: Stops polling intervals via
stopCloudPolling() - Local sessions: Cancels agent via
agent.cancel.mutate()+ unsubscribes
- Cloud sessions: Stops polling intervals via
-
Timing: Runs in
onMutatebefore API call, ensuring cleanup even if API fails -
Scope: Uses
taskIdto find all sessions for that task (handles 1-to-many)
Validation Steps
Before Fix (Reproduce Issue):
- Create task + start agent session
- Add debug log to
startCloudPolling():console.log('🔄 POLLING:', taskRunId) - Delete task
- Observe: Polling continues forever
After Fix (Verify Fix):
- Repeat same steps
- Delete task
- Observe: Polling stops immediately, no more console messages
Impact
- Lines changed: ~10 lines
- Risk: Low (only adds cleanup, no breaking changes)
- Benefit: High (fixes resource leaks, improves performance)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working