Fix goroutine leaks in sync queue processor and connection manager

Critical fixes to prevent goroutine leaks during application shutdown:

1. Sync Queue Processor:
   - Changed StartCleanupTask() to return context.CancelFunc
   - Modified to accept and watch cancellable context
   - Added queue context/cancel to Handler struct
   - Created StartBackgroundTasks() method for main handler instance
   - Cancel queue processor during shutdown in StopScheduler()

2. Connection Manager:
   - Modified StartCleanupTask() to use cancellable context
   - Returns cancel function that can be called during shutdown
   - Goroutine now properly exits when context is cancelled

3. Handler Lifecycle:
   - Added StartBackgroundTasks() to Handler
   - Only main handler instance starts background goroutines
   - Temporary handler instances (library/sync routes) don't start tasks
   - StopScheduler() now properly shuts down all background goroutines

4. Router Integration:
   - Updated SetupRoutes to accept queueProcessor parameter
   - Main scanner handler starts background tasks after creation
   - Library and sync route handlers don't start duplicate tasks

Impact:
- Fixes 2 major goroutine leaks (queue processor + connection cleanup)
- Application now properly shuts down all goroutines on exit
- No more resource leaks from long-running goroutines
- Test added to detect future goroutine regressions

Test: TestGoroutineCleanup verifies background services can be stopped.
This commit is contained in:
2026-02-09 13:12:31 -05:00
parent e758468c14
commit 001647cbbe
7 changed files with 95 additions and 11 deletions
+14 -3
View File
@@ -1,6 +1,7 @@
package sync
import (
"context"
"log"
"sync"
"time"
@@ -211,11 +212,21 @@ func (m *ConnectionManager) GetConnectionStats() map[string]int {
}
// StartCleanupTask starts a background task to cleanup stale connections
func (m *ConnectionManager) StartCleanupTask() {
func (m *ConnectionManager) StartCleanupTask() context.CancelFunc {
ticker := time.NewTicker(1 * time.Minute)
ctx, cancel := context.WithCancel(context.Background())
go func() {
for range ticker.C {
m.CleanupStaleConnections()
for {
select {
case <-ctx.Done():
ticker.Stop()
return
case <-ticker.C:
m.CleanupStaleConnections()
}
}
}()
return cancel
}