diff --git a/admin.go b/admin.go index 11efc683b..8558cee1c 100644 --- a/admin.go +++ b/admin.go @@ -262,7 +262,7 @@ func (admin *AdminConfig) newAdminHandler(addr NetworkAddress, remote bool) admi // provisionAdminRouters provisions all the router modules // in the admin.api namespace that need provisioning. -func (admin AdminConfig) provisionAdminRouters(ctx Context) error { +func (admin *AdminConfig) provisionAdminRouters(ctx Context) error { for _, router := range admin.routers { provisioner, ok := router.(Provisioner) if !ok { @@ -277,6 +277,7 @@ func (admin AdminConfig) provisionAdminRouters(ctx Context) error { // We no longer need the routers once provisioned, allow for GC admin.routers = nil + return nil } diff --git a/caddy.go b/caddy.go index 364392401..661d0b0c3 100644 --- a/caddy.go +++ b/caddy.go @@ -504,20 +504,29 @@ func finishSettingUp(ctx Context, cfg *Config) error { if cfg.Admin.Config.LoadDelay > 0 { go func() { - timer := time.NewTimer(time.Duration(cfg.Admin.Config.LoadDelay)) - select { - case <-timer.C: - loadedConfig, err := val.(ConfigLoader).LoadConfig(ctx) - if err != nil { - Log().Error("loading dynamic config failed", zap.Error(err)) - return + // the loop is here only to iterate if there is an error or a no-op config load, + // in which case we simply wait the delay and try again + for { + timer := time.NewTimer(time.Duration(cfg.Admin.Config.LoadDelay)) + select { + case <-timer.C: + loadedConfig, err := val.(ConfigLoader).LoadConfig(ctx) + if err != nil { + Log().Error("failed loading dynamic config; will retry", zap.Error(err)) + continue + } + if loadedConfig == nil { + Log().Info("dynamically-loaded config was nil; will retry") + continue + } + runLoadedConfig(loadedConfig) + case <-ctx.Done(): + if !timer.Stop() { + <-timer.C + } + Log().Info("stopping dynamic config loading") } - runLoadedConfig(loadedConfig) - case <-ctx.Done(): - if !timer.Stop() { - <-timer.C - } - Log().Info("stopping dynamic config loading") + break } }() } else { @@ -534,8 +543,10 @@ func finishSettingUp(ctx Context, cfg *Config) error { return nil } -// ConfigLoader is a type that can load a Caddy config. The -// returned config must be valid Caddy JSON. +// ConfigLoader is a type that can load a Caddy config. If +// the return value is non-nil, it must be valid Caddy JSON; +// if nil or with non-nil error, it is considered to be a +// no-op load and may be retried later. type ConfigLoader interface { LoadConfig(Context) ([]byte, error) }