SuperQ / smokeping_prober

Prometheus style smokeping
Apache License 2.0
554 stars 73 forks source link

[Feature Request] Reload configuration dynamically with signal HUP #118

Closed carlosrodfern closed 5 months ago

carlosrodfern commented 12 months ago

It would be nice to implement configuration reload with HUP. An example code is https://github.com/prometheus/blackbox_exporter/blob/c908cba63b5256af83d0553e7fb5049f709aaeac/main.go#L130

I'm planning to bring an PR for it.

carlosrodfern commented 10 months ago

Looking into it and it seems that it will be a significant refactor for little gain since the workaround is just restarting the process. I'll close this issue.

SuperQ commented 10 months ago

It would be nice to have some day.

carlosrodfern commented 10 months ago

@SuperQ , I was just going the route of getting there programmatically by refreshing the actual variables. It will definitely require a good amount of shuffling around to keep the state.

However, I have another solution that it is simpler, but the program logs would appear as if it were rebooting, and it would reset any existing state (e.g., histograms). It is using execve(2). Basically, reexec the program.

The code change would look like this:

diff --git a/main.go b/main.go
index 9357297..cbbcbcd 100644
--- a/main.go
+++ b/main.go
@@ -20,11 +20,13 @@ import (
    "net/http"
    _ "net/http/pprof"
    "os"
+   "os/signal"
    "strconv"
    "strings"
+   "syscall"
    "time"

-   "github.com/prometheus-community/pro-bing"
+   probing "github.com/prometheus-community/pro-bing"
    "github.com/superq/smokeping_prober/config"

    "github.com/alecthomas/kingpin/v2"
@@ -228,6 +230,18 @@ func main() {
        http.Handle("/", landingPage)
    }

+   hup := make(chan os.Signal, 1)
+   signal.Notify(hup, syscall.SIGHUP)
+   go func() {
+       for {
+           <-hup
+           level.Info(logger).Log("msg", "Reexecuting and reloading the configuration")
+           if err := syscall.Exec("/proc/self/exe", os.Args, os.Environ()); err != nil {
+               level.Error(logger).Log("msg", "Error reloading config", "err", err)
+           }
+       }
+   }()
+
    server := &http.Server{}
    if err := web.ListenAndServe(server, webConfig, logger); err != nil {
        level.Error(logger).Log("err", err)

That change just works. If you like this idea, I can submit a PR with these changes.

SuperQ commented 10 months ago

My plan was to not keep any state between reloads. Just stop all pingers, clear the metrics registry, and start new pingers. This makes more sense from a intention of reload signal.