Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: watch include directory #5521

Merged
merged 5 commits into from
May 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 14 additions & 39 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ func LoadConfig(configFile, adapterName string) ([]byte, string, error) {
// blocks indefinitely; it only quits if the poller has errors for
// long enough time. The filename passed in must be the actual
// 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) {
defer func() {
if err := recover(); err != nil {
Expand All @@ -189,64 +191,37 @@ func watchConfigFile(filename, adapterName string) {
With(zap.String("config_file", filename))
}

// get the initial timestamp on the config file
info, err := os.Stat(filename)
// get current config
lastCfg, _, err := LoadConfig(filename, adapterName)
if err != nil {
logger().Error("cannot watch config file", zap.Error(err))
logger().Error("unable to load latest config", zap.Error(err))
return
}
lastModified := info.ModTime()

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
//nolint:staticcheck
for range time.Tick(1 * time.Second) {
// get the file info
info, err := os.Stat(filename)

// get current config
newCfg, _, err := LoadConfig(filename, adapterName)
if err != nil {
if finalError(err) {
return
}
continue
logger().Error("unable to load latest config", zap.Error(err))
return
}
lastErr = time.Time{} // no error, so clear any memory of one

// if it hasn't changed, nothing to do
if !info.ModTime().After(lastModified) {
if bytes.Equal(lastCfg, newCfg) {
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 {
logger().Error("unable to load latest config", zap.Error(err))
continue
}
// remember the current config
lastCfg = newCfg

// apply the updated config
err = caddy.Load(config, false)
err = caddy.Load(lastCfg, false)
if err != nil {
logger().Error("applying latest config", zap.Error(err))
continue
Expand Down