Implement routing table snapshotter with automatic loading on startup
- Create snapshotter package with periodic (10 min) and on-demand snapshots - Add JSON serialization with gzip compression and atomic file writes - Update routing table to track AddedAt time for each route - Load snapshots on startup, filtering out stale routes (>30 minutes old) - Add ROUTEWATCH_DISABLE_SNAPSHOTTER env var for tests - Use OS-appropriate state directories (macOS: ~/Library/Application Support, Linux: /var/lib or XDG_STATE_HOME)
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"git.eeqj.de/sneak/routewatch/internal/metrics"
|
||||
"git.eeqj.de/sneak/routewatch/internal/routingtable"
|
||||
"git.eeqj.de/sneak/routewatch/internal/server"
|
||||
"git.eeqj.de/sneak/routewatch/internal/snapshotter"
|
||||
"git.eeqj.de/sneak/routewatch/internal/streamer"
|
||||
|
||||
"go.uber.org/fx"
|
||||
@@ -54,13 +55,14 @@ type RouteWatch struct {
|
||||
routingTable *routingtable.RoutingTable
|
||||
streamer *streamer.Streamer
|
||||
server *server.Server
|
||||
snapshotter *snapshotter.Snapshotter
|
||||
logger *slog.Logger
|
||||
maxRuntime time.Duration
|
||||
}
|
||||
|
||||
// New creates a new RouteWatch instance
|
||||
func New(deps Dependencies) *RouteWatch {
|
||||
return &RouteWatch{
|
||||
rw := &RouteWatch{
|
||||
db: deps.DB,
|
||||
routingTable: deps.RoutingTable,
|
||||
streamer: deps.Streamer,
|
||||
@@ -68,6 +70,19 @@ func New(deps Dependencies) *RouteWatch {
|
||||
logger: deps.Logger,
|
||||
maxRuntime: deps.Config.MaxRuntime,
|
||||
}
|
||||
|
||||
// Create snapshotter unless disabled (for tests)
|
||||
if os.Getenv("ROUTEWATCH_DISABLE_SNAPSHOTTER") != "1" {
|
||||
snapshotter, err := snapshotter.New(deps.RoutingTable, deps.Logger)
|
||||
if err != nil {
|
||||
deps.Logger.Error("Failed to create snapshotter", "error", err)
|
||||
// Continue without snapshotter
|
||||
} else {
|
||||
rw.snapshotter = snapshotter
|
||||
}
|
||||
}
|
||||
|
||||
return rw
|
||||
}
|
||||
|
||||
// Run starts the RouteWatch application
|
||||
@@ -97,6 +112,11 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
|
||||
// Start periodic routing table stats logging
|
||||
go rw.logRoutingTableStats(ctx)
|
||||
|
||||
// Start snapshotter if available
|
||||
if rw.snapshotter != nil {
|
||||
rw.snapshotter.Start(ctx)
|
||||
}
|
||||
|
||||
// Start streaming
|
||||
if err := rw.streamer.Start(); err != nil {
|
||||
return err
|
||||
@@ -131,6 +151,13 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
|
||||
"duration", time.Since(metrics.ConnectedSince),
|
||||
)
|
||||
|
||||
// Take final snapshot before shutdown if snapshotter is available
|
||||
if rw.snapshotter != nil {
|
||||
if err := rw.snapshotter.Shutdown(); err != nil {
|
||||
rw.logger.Error("Failed to shutdown snapshotter", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -199,10 +226,7 @@ func getModule() fx.Option {
|
||||
),
|
||||
routingtable.New,
|
||||
streamer.New,
|
||||
fx.Annotate(
|
||||
server.New,
|
||||
fx.ParamTags(``, ``, ``, ``),
|
||||
),
|
||||
server.New,
|
||||
New,
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user