feature: watch include directory (#5521)

Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
This commit is contained in:
Yehonatan Ezron 2023-05-09 01:49:16 +03:00 committed by GitHub
parent bef1a739db
commit 571fc034d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -174,6 +174,8 @@ func LoadConfig(configFile, adapterName string) ([]byte, string, error) {
// blocks indefinitely; it only quits if the poller has errors for // blocks indefinitely; it only quits if the poller has errors for
// long enough time. The filename passed in must be the actual // long enough time. The filename passed in must be the actual
// config file used, not one to be discovered. // config file used, not one to be discovered.
// Each second the config files is loaded and parsed into an object
// and is compared to the last config object that was loaded
func watchConfigFile(filename, adapterName string) { func watchConfigFile(filename, adapterName string) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
@ -189,64 +191,37 @@ func watchConfigFile(filename, adapterName string) {
With(zap.String("config_file", filename)) With(zap.String("config_file", filename))
} }
// get the initial timestamp on the config file // get current config
info, err := os.Stat(filename) lastCfg, _, err := LoadConfig(filename, adapterName)
if err != nil { if err != nil {
logger().Error("cannot watch config file", zap.Error(err)) logger().Error("unable to load latest config", zap.Error(err))
return return
} }
lastModified := info.ModTime()
logger().Info("watching config file for changes") logger().Info("watching config file for changes")
// if the file disappears or something, we can
// stop polling if the error lasts long enough
var lastErr time.Time
finalError := func(err error) bool {
if lastErr.IsZero() {
lastErr = time.Now()
return false
}
if time.Since(lastErr) > 30*time.Second {
logger().Error("giving up watching config file; too many errors",
zap.Error(err))
return true
}
return false
}
// begin poller // begin poller
//nolint:staticcheck //nolint:staticcheck
for range time.Tick(1 * time.Second) { for range time.Tick(1 * time.Second) {
// get the file info
info, err := os.Stat(filename)
if err != nil {
if finalError(err) {
return
}
continue
}
lastErr = time.Time{} // no error, so clear any memory of one
// if it hasn't changed, nothing to do // get current config
if !info.ModTime().After(lastModified) { newCfg, _, err := LoadConfig(filename, adapterName)
continue
}
logger().Info("config file changed; reloading")
// remember this timestamp
lastModified = info.ModTime()
// load the contents of the file
config, _, err := LoadConfig(filename, adapterName)
if err != nil { if err != nil {
logger().Error("unable to load latest config", zap.Error(err)) logger().Error("unable to load latest config", zap.Error(err))
continue return
} }
// if it hasn't changed, nothing to do
if bytes.Equal(lastCfg, newCfg) {
continue
}
logger().Info("config file changed; reloading")
// remember the current config
lastCfg = newCfg
// apply the updated config // apply the updated config
err = caddy.Load(config, false) err = caddy.Load(lastCfg, false)
if err != nil { if err != nil {
logger().Error("applying latest config", zap.Error(err)) logger().Error("applying latest config", zap.Error(err))
continue continue