diff options
author | 王清雨 <[email protected]> | 2021-07-29 05:39:08 +0800 |
---|---|---|
committer | GitHub <[email protected]> | 2021-07-28 15:39:08 -0600 |
commit | c131339c5cda3a541223fde4a714aab55de13b9a (patch) | |
tree | 8f5e82cf3596bb78497266e287e7f81e6ef35cc5 | |
parent | b6f51254ea2dcb29dde0ffb4076802505a43ace1 (diff) | |
download | caddy-c131339c5cda3a541223fde4a714aab55de13b9a.tar.gz caddy-c131339c5cda3a541223fde4a714aab55de13b9a.zip |
admin: Implement load_interval to pull config on a timer (#4246)
* feat: implement a simple timer to pull config
mostly referenced to the issue
re #4106
* Update admin.go
use `caddy.Duration`
Co-authored-by: Matt Holt <[email protected]>
* Update caddy.go
Co-authored-by: Matt Holt <[email protected]>
* Update admin.go
Co-authored-by: Francis Lavoie <[email protected]>
* fix: sync load config when no pull interval provided
try not to make break change
* fix: change PullInterval to LoadInterval
* fix: change pull_interval to load_interval
* Update caddy.go
Co-authored-by: Matt Holt <[email protected]>
Co-authored-by: Matt Holt <[email protected]>
Co-authored-by: Francis Lavoie <[email protected]>
-rw-r--r-- | admin.go | 6 | ||||
-rw-r--r-- | caddy.go | 44 |
2 files changed, 38 insertions, 12 deletions
@@ -109,6 +109,12 @@ type ConfigSettings struct { // // EXPERIMENTAL: Subject to change. LoadRaw json.RawMessage `json:"load,omitempty" caddy:"namespace=caddy.config_loaders inline_key=module"` + + // The interval to pull config. With a non-zero value, will pull config + // from config loader (eg. a http loader) with given interval. + // + // EXPERIMENTAL: Subject to change. + LoadInterval Duration `json:"load_interval,omitempty"` } // IdentityConfig configures management of this server's identity. An identity @@ -268,8 +268,9 @@ func unsyncedDecodeAndRun(cfgJSON []byte, allowPersist bool) error { newCfg != nil && newCfg.Admin != nil && newCfg.Admin.Config != nil && - newCfg.Admin.Config.LoadRaw != nil { - return fmt.Errorf("recursive config loading detected: pulled configs cannot pull other configs") + newCfg.Admin.Config.LoadRaw != nil && + newCfg.Admin.Config.LoadInterval <= 0 { + return fmt.Errorf("recursive config loading detected: pulled configs cannot pull other configs without positive load_interval") } // run the new config and start all its apps @@ -480,23 +481,42 @@ func finishSettingUp(ctx Context, cfg *Config) error { if err != nil { return fmt.Errorf("loading config loader module: %s", err) } - loadedConfig, err := val.(ConfigLoader).LoadConfig(ctx) - if err != nil { - return fmt.Errorf("loading dynamic config from %T: %v", val, err) - } - - // do this in a goroutine so current config can finish being loaded; otherwise deadlock - go func() { - Log().Info("applying dynamically-loaded config", zap.String("loader_module", val.(Module).CaddyModule().ID.Name())) + runLoadedConfig := func(config []byte) { + Log().Info("applying dynamically-loaded config", zap.String("loader_module", val.(Module).CaddyModule().ID.Name()), zap.Int("pull_interval", int(cfg.Admin.Config.LoadInterval))) currentCfgMu.Lock() - err := unsyncedDecodeAndRun(loadedConfig, false) + err := unsyncedDecodeAndRun(config, false) currentCfgMu.Unlock() if err == nil { Log().Info("dynamically-loaded config applied successfully") } else { Log().Error("running dynamically-loaded config failed", zap.Error(err)) } - }() + } + if cfg.Admin.Config.LoadInterval > 0 { + go func() { + select { + // if LoadInterval is positive, will wait for the interval and then run with new config + case <-time.After(time.Duration(cfg.Admin.Config.LoadInterval)): + loadedConfig, err := val.(ConfigLoader).LoadConfig(ctx) + if err != nil { + Log().Error("loading dynamic config failed", zap.Error(err)) + return + } + runLoadedConfig(loadedConfig) + case <-ctx.Done(): + return + } + }() + } else { + // if no LoadInterval is provided, will load config synchronously + loadedConfig, err := val.(ConfigLoader).LoadConfig(ctx) + if err != nil { + return fmt.Errorf("loading dynamic config from %T: %v", val, err) + } + // do this in a goroutine so current config can finish being loaded; otherwise deadlock + go runLoadedConfig(loadedConfig) + } + } return nil |