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:
@@ -24,6 +24,9 @@ type Handler struct {
|
||||
scanner *services.MediaScanner
|
||||
worker *services.Worker
|
||||
scheduler *services.Scheduler
|
||||
queueProcessor *wsync.SyncQueueProcessor
|
||||
queueCtx context.Context
|
||||
queueCancel context.CancelFunc
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
mu sync.Mutex
|
||||
@@ -31,13 +34,16 @@ type Handler struct {
|
||||
watchModeCancel context.CancelFunc
|
||||
watchingLibraries map[string]bool
|
||||
connManager *wsync.ConnectionManager
|
||||
cleanupTaskCancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewHandler(db *database.Queries, connManager *wsync.ConnectionManager) *Handler {
|
||||
func NewHandler(db *database.Queries, connManager *wsync.ConnectionManager, queueProcessor *wsync.SyncQueueProcessor) *Handler {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
worker := services.NewWorker(3)
|
||||
scheduler := services.NewScheduler(worker, db)
|
||||
|
||||
queueCtx, queueCancel := context.WithCancel(context.Background())
|
||||
|
||||
watchCtx, watchCancel := context.WithCancel(context.Background())
|
||||
|
||||
return &Handler{
|
||||
@@ -45,6 +51,9 @@ func NewHandler(db *database.Queries, connManager *wsync.ConnectionManager) *Han
|
||||
scanner: services.NewMediaScanner(db),
|
||||
worker: worker,
|
||||
scheduler: scheduler,
|
||||
queueProcessor: queueProcessor,
|
||||
queueCtx: queueCtx,
|
||||
queueCancel: queueCancel,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
watchModeCtx: watchCtx,
|
||||
@@ -54,6 +63,13 @@ func NewHandler(db *database.Queries, connManager *wsync.ConnectionManager) *Han
|
||||
}
|
||||
}
|
||||
|
||||
// StartBackgroundTasks starts the queue processor and cleanup task
|
||||
// This should be called once for the main handler instance
|
||||
func (h *Handler) StartBackgroundTasks() {
|
||||
h.cleanupTaskCancel = h.connManager.StartCleanupTask()
|
||||
go h.queueProcessor.Start(h.queueCtx)
|
||||
}
|
||||
|
||||
// parseDate parses a date string in YYYY-MM-DD format
|
||||
func parseDate(dateStr string) time.Time {
|
||||
if dateStr == "" {
|
||||
@@ -65,8 +81,8 @@ func parseDate(dateStr string) time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func SetupRoutes(g *echo.Group, db *database.Queries, connManager *wsync.ConnectionManager) *Handler {
|
||||
return NewHandler(db, connManager)
|
||||
func SetupRoutes(g *echo.Group, db *database.Queries, connManager *wsync.ConnectionManager, queueProcessor *wsync.SyncQueueProcessor) *Handler {
|
||||
return NewHandler(db, connManager, queueProcessor)
|
||||
}
|
||||
|
||||
// ScanLibraryRequest represents the request for scanning a library
|
||||
@@ -380,4 +396,14 @@ func (h *Handler) StartScheduler() {
|
||||
func (h *Handler) StopScheduler() {
|
||||
h.scheduler.Stop()
|
||||
h.worker.Shutdown()
|
||||
|
||||
// Stop the sync queue processor
|
||||
if h.queueCancel != nil {
|
||||
h.queueCancel()
|
||||
}
|
||||
|
||||
// Stop connection manager cleanup task
|
||||
if h.cleanupTaskCancel != nil {
|
||||
h.cleanupTaskCancel()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user