From 0028383f3ad2c7eb5f5dd8cd9953da4cc5e696b8 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Wed, 22 Oct 2025 16:37:18 +0000 Subject: [PATCH 1/2] Fix(a2a): Fix task cancellation race condition Fix bug where A2A task cancellation didn't work properly. The issue was that CancelBackgroundTask() was using a stale copy of TaskPollingState from GetBackgroundTasks() instead of getting the live polling state from the task tracker. This caused: 1. Tasks to disappear from the UI task list (cleanup was called) 2. But the actual background polling goroutine continued running 3. A2A server never received the cancellation request The fix gets the live polling state directly from taskTracker.GetPollingState() which ensures the correct CancelFunc is called to stop the active goroutine. Fixes #195 Co-authored-by: Eden Reich --- internal/services/background_task_service.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/internal/services/background_task_service.go b/internal/services/background_task_service.go index a5cdbcb..69d48f6 100644 --- a/internal/services/background_task_service.go +++ b/internal/services/background_task_service.go @@ -55,16 +55,12 @@ func (s *BackgroundTaskService) CancelBackgroundTask(taskID string) error { logger.Info("Canceling background task", "task_id", taskID) - backgroundTasks := s.GetBackgroundTasks() - - var targetTask *domain.TaskPollingState - for i := range backgroundTasks { - if backgroundTasks[i].TaskID == taskID { - targetTask = &backgroundTasks[i] - break - } + if s.taskTracker == nil { + return fmt.Errorf("task tracker not available") } + // Get the live polling state directly from the tracker instead of using a copy + targetTask := s.taskTracker.GetPollingState(taskID) if targetTask == nil { return fmt.Errorf("task %s not found in background tasks", taskID) } @@ -75,14 +71,14 @@ func (s *BackgroundTaskService) CancelBackgroundTask(taskID string) error { logger.Info("Successfully sent cancel request to agent", "task_id", taskID) } + // Call the cancel function from the live polling state to actually stop the goroutine if targetTask.CancelFunc != nil { targetTask.CancelFunc() } - if s.taskTracker != nil { - s.taskTracker.StopPolling(taskID) - s.taskTracker.RemoveTask(taskID) - } + // Clean up the task from the tracker + s.taskTracker.StopPolling(taskID) + s.taskTracker.RemoveTask(taskID) logger.Info("Task cancelled successfully", "task_id", taskID) return nil From 798c09e5eebe2a8a6c070146f047ee9eee3b281d Mon Sep 17 00:00:00 2001 From: Eden Reich Date: Wed, 22 Oct 2025 18:42:42 +0200 Subject: [PATCH 2/2] chore: Remove redundant comments --- internal/services/background_task_service.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/services/background_task_service.go b/internal/services/background_task_service.go index 69d48f6..20efb3f 100644 --- a/internal/services/background_task_service.go +++ b/internal/services/background_task_service.go @@ -59,7 +59,6 @@ func (s *BackgroundTaskService) CancelBackgroundTask(taskID string) error { return fmt.Errorf("task tracker not available") } - // Get the live polling state directly from the tracker instead of using a copy targetTask := s.taskTracker.GetPollingState(taskID) if targetTask == nil { return fmt.Errorf("task %s not found in background tasks", taskID) @@ -71,12 +70,10 @@ func (s *BackgroundTaskService) CancelBackgroundTask(taskID string) error { logger.Info("Successfully sent cancel request to agent", "task_id", taskID) } - // Call the cancel function from the live polling state to actually stop the goroutine if targetTask.CancelFunc != nil { targetTask.CancelFunc() } - // Clean up the task from the tracker s.taskTracker.StopPolling(taskID) s.taskTracker.RemoveTask(taskID)