Skip to content

Commit

Permalink
core: Retry dynamic config load if error or no-op (#4603)
Browse files Browse the repository at this point in the history
Also fix ineffectual assignment (unrelated)
  • Loading branch information
mholt committed Mar 3, 2022
1 parent f5e1049 commit ceef70d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 16 deletions.
3 changes: 2 additions & 1 deletion admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down
41 changes: 26 additions & 15 deletions caddy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down

0 comments on commit ceef70d

Please sign in to comment.