feat: use sd_notify for watchdog and status notification
1 file changed, 57 insertions(+), 4 deletions(-)
changed files
M cmd/searchix-web/serve.go → cmd/searchix-web/serve.go
@@ -3,13 +3,16 @@ import ( "context" "errors" + "math" "os" "os/signal" "sync" "syscall" + "time" "github.com/Southclaws/fault" "github.com/Southclaws/fault/fmsg" + "github.com/ecnepsnai/sdnotify" "golang.org/x/term" "alin.ovh/searchix/internal/file"@@ -28,9 +31,6 @@ signals := []os.Signal{os.Interrupt, syscall.SIGTERM} if term.IsTerminal(int(os.Stdout.Fd())) { signals = append(signals, syscall.SIGHUP) } - - ctx, cancel := signal.NotifyContext(context.Background(), signals...) - defer cancel() root, err := file.CreateAndOpenRoot(cfg.DataPath) if err != nil {@@ -88,7 +88,15 @@ if err != nil { return fault.Wrap(err, fmsg.With("Failed to create importer")) } + ctx, stop := signal.NotifyContext(context.Background(), signals...) + defer stop() + if store.IsNew() { + err = sdnotify.Status("fetching") + if err != nil { + logger.Warn("failed to update systemd status", "error", err) + } + err = imp.Fetch(ctx, true, false, nil) if err != nil { return fault.Wrap(err, fmsg.With("Failed to start importer"))@@ -120,9 +128,19 @@ logger.Fatal("error", "error", err) } }() + err = sdnotify.Ready() + if err != nil { + logger.Fatal("failed to notify systemd of readiness", "error", err) + } + reimport := make(chan os.Signal, 1) go func() { for sig := range reimport { + err := sdnotify.Status("re-indexing") + if err != nil { + logger.Warn("failed to update systemd status", "error", err) + } + if sig == syscall.SIGUSR1 { logger.Info("manual fetch on SIGUSR1") err := imp.Fetch(ctx, true, false, nil)@@ -133,7 +151,7 @@ logger.Info("manual fetch succeeded") } logger.Info("manual re-index", "signal", sig.String()) - err := imp.Index(ctx) + err = imp.Index(ctx) if err != nil { logger.Error("manual index error", "error", err) }@@ -146,6 +164,11 @@ if err != nil { logger.Error("manual prune error", "error", err) } logger.Info("manual prune completed") + } + + err = sdnotify.Status("completed manual re-index") + if err != nil { + logger.Warn("failed to update systemd status", "error", err) } } }()@@ -157,9 +180,39 @@ defer wg.Done() imp.StartUpdateTimer(ctx) }() + if wdu, defined := os.LookupEnv("WATCHDOG_USEC"); defined { + wd, err := time.ParseDuration(wdu + "us") + if err != nil { + logger.Fatal("could not parse WATCHDOG_USEC", "value", wdu) + } + tickRate := time.Duration(math.Ceil(wd.Seconds()*0.75)) * time.Second + + wg.Add(1) + go func() { + defer wg.Done() + for range time.Tick(tickRate) { + err := sdnotify.Watchdog() + if err != nil { + logger.Warn("") + } + } + }() + } + <-ctx.Done() + stop() + + logger.Debug("stopping server") + err = sdnotify.Stopping() + if err != nil { + logger.Warn("failed to notify systemd of shutdown", "error", err) + } s.Stop() + + logger.Debug("waiting for tasks") wg.Wait() + + logger.Info("done") return }