Resilient HAProxy config: isolate broken services on validation failure
When haproxy -c fails, parse ALERT line numbers, map to service domains via # service: comments in generated config, exclude broken services, and regenerate. One retry — prevents a single bad registration from blocking all config updates.
This commit is contained in:
@@ -122,13 +122,51 @@ func (api *API) reconcileNetworking() {
|
||||
}
|
||||
|
||||
// Generate and write HAProxy config
|
||||
haproxyCfg := api.haproxy.GenerateWithOpts(instanceRoutes, nil, haproxy.GenerateOpts{
|
||||
genOpts := haproxy.GenerateOpts{
|
||||
HTTPRoutes: activeHTTPRoutes,
|
||||
CertsDir: certsDir,
|
||||
})
|
||||
}
|
||||
haproxyCfg := api.haproxy.GenerateWithOpts(instanceRoutes, nil, genOpts)
|
||||
|
||||
if err := api.haproxy.WriteConfig(haproxyCfg); err != nil {
|
||||
slog.Error("reconcile: failed to write HAProxy config", "error", err)
|
||||
// Validation failed — identify and exclude broken services, then retry
|
||||
brokenDomains := haproxy.FindBrokenServices(haproxyCfg, haproxy.ParseValidationErrors(err.Error()))
|
||||
if len(brokenDomains) > 0 {
|
||||
slog.Error("reconcile: excluding broken services and retrying",
|
||||
"broken", brokenDomains, "error", err)
|
||||
|
||||
exclude := map[string]bool{}
|
||||
for _, d := range brokenDomains {
|
||||
exclude[d] = true
|
||||
}
|
||||
|
||||
var filteredInstances []haproxy.InstanceRoute
|
||||
for _, r := range instanceRoutes {
|
||||
if !exclude[r.Domain] {
|
||||
filteredInstances = append(filteredInstances, r)
|
||||
}
|
||||
}
|
||||
var filteredHTTP []haproxy.HTTPRoute
|
||||
for _, r := range activeHTTPRoutes {
|
||||
if !exclude[r.Domain] {
|
||||
filteredHTTP = append(filteredHTTP, r)
|
||||
}
|
||||
}
|
||||
|
||||
genOpts.HTTPRoutes = filteredHTTP
|
||||
haproxyCfg = api.haproxy.GenerateWithOpts(filteredInstances, nil, genOpts)
|
||||
if err := api.haproxy.WriteConfig(haproxyCfg); err != nil {
|
||||
slog.Error("reconcile: retry also failed", "error", err)
|
||||
} else {
|
||||
if err := api.haproxy.ReloadService(); err != nil {
|
||||
slog.Warn("reconcile: failed to reload HAProxy", "error", err)
|
||||
} else {
|
||||
api.broadcastHaproxyEvent("haproxy:config", "HAProxy config regenerated (excluded broken services)")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slog.Error("reconcile: failed to write HAProxy config (no broken services identified)", "error", err)
|
||||
}
|
||||
} else {
|
||||
if err := api.haproxy.ReloadService(); err != nil {
|
||||
slog.Warn("reconcile: failed to reload HAProxy", "error", err)
|
||||
|
||||
Reference in New Issue
Block a user