root: config: implement config watching
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
parent
2a15004232
commit
969ec188a7
1
go.mod
1
go.mod
|
@ -42,6 +42,7 @@ require (
|
|||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 // indirect
|
||||
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect
|
||||
|
|
3
go.sum
3
go.sum
|
@ -66,6 +66,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/garyburd/redigo v1.6.4 h1:LFu2R3+ZOPgSMWMOL+saa/zXRjw0ID2G8FepO53BGlg=
|
||||
github.com/garyburd/redigo v1.6.4/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
|
||||
github.com/getsentry/sentry-go v0.20.0 h1:bwXW98iMRIWxn+4FgPW7vMrjmbym6HblXALmhjHmQaQ=
|
||||
|
@ -486,6 +488,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
|
@ -8,8 +8,10 @@ import (
|
|||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
env "github.com/Netflix/go-env"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
@ -53,6 +55,71 @@ func getConfigPaths() []string {
|
|||
return computedConfigPaths
|
||||
}
|
||||
|
||||
func WatchChanges(callback func()) (*fsnotify.Watcher, error) {
|
||||
configPaths := getConfigPaths()
|
||||
|
||||
w, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start listening for events
|
||||
go func() {
|
||||
reload := false
|
||||
for {
|
||||
select {
|
||||
// Read from errors
|
||||
case err, ok := <-w.Errors:
|
||||
if !ok {
|
||||
// Channel was closed (i.e. Watcher.Close() was called)
|
||||
return
|
||||
}
|
||||
log.WithError(err).Warning("failed to watch for file changes")
|
||||
// Read from events
|
||||
case ev, ok := <-w.Events:
|
||||
if !ok {
|
||||
// Channel was closed (i.e. Watcher.Close() was called)
|
||||
return
|
||||
}
|
||||
|
||||
// Ignores files we're not interested in
|
||||
// We get the whole list again in case a file in a directory we're watching was created
|
||||
// and that file is of interest
|
||||
for _, f := range getConfigPaths() {
|
||||
if f == ev.Name {
|
||||
reload = true
|
||||
log.Debugf("%s file change, setting configuration to be reloaded", ev.Name)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if reload {
|
||||
log.Infof("configuration files changed, reloading configuration")
|
||||
Reload()
|
||||
callback()
|
||||
// Cooldown after configuration reloading
|
||||
time.Sleep(14 * time.Second)
|
||||
}
|
||||
// Otherwise `select` fires all of the time
|
||||
time.Sleep(1 * time.Second)
|
||||
reload = false
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Register the files to be watch
|
||||
for _, p := range configPaths {
|
||||
// Actually, watch the directory, not the files, as that's how fsnotify works
|
||||
// We assume we're only getting valid files as getConfigPaths already handles all the necessary checks
|
||||
err = w.Add(filepath.Dir(p))
|
||||
log.Warningf("watching for changes for file %s in dir %s", p, filepath.Dir(p))
|
||||
if err != nil {
|
||||
return w, err
|
||||
}
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func Get() *Config {
|
||||
if cfg == nil {
|
||||
c := &Config{}
|
||||
|
@ -62,6 +129,12 @@ func Get() *Config {
|
|||
return cfg
|
||||
}
|
||||
|
||||
func Reload() {
|
||||
c := &Config{}
|
||||
c.Setup(getConfigPaths()...)
|
||||
cfg = c
|
||||
}
|
||||
|
||||
func (c *Config) Setup(paths ...string) {
|
||||
for _, path := range paths {
|
||||
err := c.LoadConfig(path)
|
||||
|
|
Reference in a new issue