fixed healthcheck failed to disable and nil dereference

This commit is contained in:
yusing 2024-10-19 00:13:55 +08:00
parent 53557e38b6
commit b296fb2965
11 changed files with 60 additions and 20 deletions

View file

@ -31,6 +31,7 @@ func NewHandler() http.Handler {
mux.HandleFunc("POST", "/v1/reload", v1.Reload) mux.HandleFunc("POST", "/v1/reload", v1.Reload)
mux.HandleFunc("GET", "/v1/list", v1.List) mux.HandleFunc("GET", "/v1/list", v1.List)
mux.HandleFunc("GET", "/v1/list/{what}", v1.List) mux.HandleFunc("GET", "/v1/list/{what}", v1.List)
mux.HandleFunc("GET", "/v1/list/{what}/{which}", v1.List)
mux.HandleFunc("GET", "/v1/file", v1.GetFileContent) mux.HandleFunc("GET", "/v1/file", v1.GetFileContent)
mux.HandleFunc("GET", "/v1/file/{filename...}", v1.GetFileContent) mux.HandleFunc("GET", "/v1/file/{filename...}", v1.GetFileContent)
mux.HandleFunc("POST", "/v1/file/{filename...}", v1.SetFileContent) mux.HandleFunc("POST", "/v1/file/{filename...}", v1.SetFileContent)

View file

@ -14,6 +14,7 @@ import (
) )
const ( const (
ListRoute = "route"
ListRoutes = "routes" ListRoutes = "routes"
ListConfigFiles = "config_files" ListConfigFiles = "config_files"
ListMiddlewares = "middlewares" ListMiddlewares = "middlewares"
@ -28,8 +29,16 @@ func List(w http.ResponseWriter, r *http.Request) {
if what == "" { if what == "" {
what = ListRoutes what = ListRoutes
} }
which := r.PathValue("which")
switch what { switch what {
case ListRoute:
if route := listRoute(which); route == nil {
http.Error(w, "not found", http.StatusNotFound)
return
} else {
U.RespondJSON(w, r, route)
}
case ListRoutes: case ListRoutes:
U.RespondJSON(w, r, config.RoutesByAlias(route.RouteType(r.FormValue("type")))) U.RespondJSON(w, r, config.RoutesByAlias(route.RouteType(r.FormValue("type"))))
case ListConfigFiles: case ListConfigFiles:
@ -49,6 +58,21 @@ func List(w http.ResponseWriter, r *http.Request) {
} }
} }
func listRoute(which string) any {
if which == "" {
which = "all"
}
if which == "all" {
return config.RoutesByAlias()
}
routes := config.RoutesByAlias()
route, ok := routes[which]
if !ok {
return nil
}
return route
}
func listConfigFiles(w http.ResponseWriter, r *http.Request) { func listConfigFiles(w http.ResponseWriter, r *http.Request) {
files, err := utils.ListFiles(common.ConfigBasePath, 1) files, err := utils.ListFiles(common.ConfigBasePath, 1)
if err != nil { if err != nil {

View file

@ -64,5 +64,5 @@ func UseIdleWatcher(entry Entry) bool {
func UseHealthCheck(entry Entry) bool { func UseHealthCheck(entry Entry) bool {
hc := entry.HealthCheckConfig() hc := entry.HealthCheckConfig()
return hc != nil && !hc.Disabled return hc != nil && !hc.Disable
} }

View file

@ -126,15 +126,15 @@ func (e *RawEntry) FillMissingFields() {
e.HealthCheck = new(health.HealthCheckConfig) e.HealthCheck = new(health.HealthCheckConfig)
} }
if e.HealthCheck.Disabled {
e.HealthCheck = nil
} else {
if e.HealthCheck.Interval == 0 { if e.HealthCheck.Interval == 0 {
e.HealthCheck.Interval = common.HealthCheckIntervalDefault e.HealthCheck.Interval = common.HealthCheckIntervalDefault
} }
if e.HealthCheck.Timeout == 0 { if e.HealthCheck.Timeout == 0 {
e.HealthCheck.Timeout = common.HealthCheckTimeoutDefault e.HealthCheck.Timeout = common.HealthCheckTimeoutDefault
} }
if e.HealthCheck.Disable {
e.HealthCheck = nil
} }
if cont.IdleTimeout != "" { if cont.IdleTimeout != "" {

View file

@ -106,9 +106,12 @@ func (r *HTTPRoute) Start(providerSubtask task.Task) E.NestedError {
httpRoutesMu.Lock() httpRoutesMu.Lock()
defer httpRoutesMu.Unlock() defer httpRoutesMu.Unlock()
if r.HealthCheck.Disabled && (entry.UseLoadBalance(r) || entry.UseIdleWatcher(r)) { if !entry.UseHealthCheck(r) && (entry.UseLoadBalance(r) || entry.UseIdleWatcher(r)) {
logrus.Warnf("%s.healthCheck.disabled cannot be false when loadbalancer or idlewatcher is enabled", r.Alias) logrus.Warnf("%s.healthCheck.disabled cannot be false when loadbalancer or idlewatcher is enabled", r.Alias)
r.HealthCheck.Disabled = true if r.HealthCheck == nil {
r.HealthCheck = new(health.HealthCheckConfig)
}
r.HealthCheck.Disable = true
} }
switch { switch {
@ -121,6 +124,7 @@ func (r *HTTPRoute) Start(providerSubtask task.Task) E.NestedError {
r.handler = waker r.handler = waker
r.HealthMon = waker r.HealthMon = waker
case entry.UseHealthCheck(r): case entry.UseHealthCheck(r):
logrus.Debugf("%s health check: %+v", r.Alias, r.HealthCheck)
r.HealthMon = health.NewHTTPHealthMonitor(r.TargetURL(), r.HealthCheck, r.rp.Transport) r.HealthMon = health.NewHTTPHealthMonitor(r.TargetURL(), r.HealthCheck, r.rp.Transport)
} }
r.task = providerSubtask r.task = providerSubtask

View file

@ -61,6 +61,8 @@ func (p *FileProvider) LoadRoutesImpl() (routes R.Routes, res E.NestedError) {
return return
} }
b.Add(Validate(data))
return R.FromEntries(entries) return R.FromEntries(entries)
} }

View file

@ -66,9 +66,9 @@ func (r *StreamRoute) Start(providerSubtask task.Task) E.NestedError {
streamRoutesMu.Lock() streamRoutesMu.Lock()
defer streamRoutesMu.Unlock() defer streamRoutesMu.Unlock()
if r.HealthCheck.Disabled && (entry.UseLoadBalance(r) || entry.UseIdleWatcher(r)) { if r.HealthCheck.Disable && (entry.UseLoadBalance(r) || entry.UseIdleWatcher(r)) {
logrus.Warnf("%s.healthCheck.disabled cannot be false when loadbalancer or idlewatcher is enabled", r.Alias) logrus.Warnf("%s.healthCheck.disabled cannot be false when loadbalancer or idlewatcher is enabled", r.Alias)
r.HealthCheck.Disabled = true r.HealthCheck.Disable = true
} }
if r.Scheme.ListeningScheme.IsTCP() { if r.Scheme.ListeningScheme.IsTCP() {

View file

@ -160,7 +160,11 @@ func (t *task) Context() context.Context {
} }
func (t *task) FinishCause() error { func (t *task) FinishCause() error {
return context.Cause(t.ctx) cause := context.Cause(t.ctx)
if cause == nil {
return t.ctx.Err()
}
return cause
} }
func (t *task) Parent() Task { func (t *task) Parent() Task {

View file

@ -7,7 +7,7 @@ import (
) )
type HealthCheckConfig struct { type HealthCheckConfig struct {
Disabled bool `json:"disabled,omitempty" yaml:"disabled"` Disable bool `json:"disable,omitempty" yaml:"disable"`
Path string `json:"path,omitempty" yaml:"path"` Path string `json:"path,omitempty" yaml:"path"`
UseGet bool `json:"use_get,omitempty" yaml:"use_get"` UseGet bool `json:"use_get,omitempty" yaml:"use_get"`
Interval time.Duration `json:"interval" yaml:"interval"` Interval time.Duration `json:"interval" yaml:"interval"`

View file

@ -75,20 +75,25 @@ func (mon *monitor) Start(routeSubtask task.Task) E.NestedError {
mon.service = routeSubtask.Parent().Name() mon.service = routeSubtask.Parent().Name()
mon.task = routeSubtask mon.task = routeSubtask
if err := mon.checkUpdateHealth(); err != nil { if mon.config.Interval <= 0 {
mon.task.Finish(fmt.Sprintf("healthchecker %s failure: %s", mon.service, err)) return E.Invalid("interval", mon.config.Interval)
return err
} }
go func() { go func() {
defer func() { defer func() {
monMap.Delete(mon.task.Name())
if mon.status.Load() != StatusError { if mon.status.Load() != StatusError {
mon.status.Store(StatusUnknown) mon.status.Store(StatusUnknown)
} }
mon.task.Finish(mon.task.FinishCause().Error()) mon.task.Finish(mon.task.FinishCause().Error())
}() }()
if err := mon.checkUpdateHealth(); err != nil {
logger.Errorf("healthchecker %s failure: %s", mon.service, err)
return
}
monMap.Store(mon.service, mon) monMap.Store(mon.service, mon)
defer monMap.Delete(mon.service)
ticker := time.NewTicker(mon.config.Interval) ticker := time.NewTicker(mon.config.Interval)
defer ticker.Stop() defer ticker.Stop()

View file

@ -149,7 +149,7 @@
"healthcheck": { "healthcheck": {
"type": "object", "type": "object",
"properties": { "properties": {
"disabled": { "disable": {
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },