Fix shutdown sequence to ensure final snapshot is taken

- Add Shutdown() method to RouteWatch with mutex-protected shutdown flag
- Move all cleanup logic from Run() to Shutdown()
- Call Shutdown() from fx OnStop hook
- This ensures snapshotter gets called during graceful shutdown
This commit is contained in:
Jeffrey Paul 2025-07-28 00:11:54 +02:00
parent 52cdcd5785
commit fa9b086629
2 changed files with 21 additions and 3 deletions

View File

@ -8,6 +8,7 @@ import (
"log/slog"
"os"
"strings"
"sync"
"time"
"git.eeqj.de/sneak/routewatch/internal/database"
@ -58,6 +59,8 @@ type RouteWatch struct {
snapshotter *snapshotter.Snapshotter
logger *slog.Logger
maxRuntime time.Duration
shutdown bool
mu sync.Mutex
}
// New creates a new RouteWatch instance
@ -130,6 +133,20 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
// Wait for context cancellation
<-ctx.Done()
return nil
}
// Shutdown performs graceful shutdown of all services
func (rw *RouteWatch) Shutdown() {
rw.mu.Lock()
if rw.shutdown {
rw.mu.Unlock()
return
}
rw.shutdown = true
rw.mu.Unlock()
// Stop services
rw.streamer.Stop()
@ -153,15 +170,15 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
// Take final snapshot before shutdown if snapshotter is available
if rw.snapshotter != nil {
rw.logger.Info("Shutting down snapshotter")
rw.logger.Info("Taking final snapshot before shutdown")
if err := rw.snapshotter.Shutdown(); err != nil {
rw.logger.Error("Failed to shutdown snapshotter", "error", err)
} else {
rw.logger.Info("Final snapshot completed")
}
} else {
rw.logger.Info("No snapshotter available")
}
return nil
}
// logRoutingTableStats periodically logs routing table statistics

View File

@ -40,6 +40,7 @@ func CLIEntry() {
},
OnStop: func(_ context.Context) error {
logger.Info("Shutting down RouteWatch")
rw.Shutdown()
return nil
},