mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-24 18:11:19 +01:00
197 lines
4.8 KiB
Go
197 lines
4.8 KiB
Go
package types
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/bytedance/sonic"
|
|
strutils "github.com/yusing/goutils/strings"
|
|
"github.com/yusing/goutils/task"
|
|
)
|
|
|
|
type (
|
|
HealthStatus uint8
|
|
|
|
HealthCheckResult struct {
|
|
Healthy bool `json:"healthy"`
|
|
Detail string `json:"detail"`
|
|
Latency time.Duration `json:"latency"`
|
|
} // @name HealthCheckResult
|
|
WithHealthInfo interface {
|
|
Status() HealthStatus
|
|
Uptime() time.Duration
|
|
Latency() time.Duration
|
|
Detail() string
|
|
}
|
|
HealthMonitor interface {
|
|
task.TaskStarter
|
|
task.TaskFinisher
|
|
fmt.Stringer
|
|
WithHealthInfo
|
|
Name() string
|
|
json.Marshaler
|
|
}
|
|
HealthChecker interface {
|
|
CheckHealth() (result HealthCheckResult, err error)
|
|
URL() *url.URL
|
|
Config() *HealthCheckConfig
|
|
UpdateURL(url *url.URL)
|
|
}
|
|
HealthMonCheck interface {
|
|
HealthMonitor
|
|
HealthChecker
|
|
}
|
|
HealthJSON struct {
|
|
Name string `json:"name"`
|
|
Config *HealthCheckConfig `json:"config"`
|
|
Started int64 `json:"started"`
|
|
StartedStr string `json:"startedStr"`
|
|
Status string `json:"status"`
|
|
Uptime float64 `json:"uptime"`
|
|
UptimeStr string `json:"uptimeStr"`
|
|
Latency float64 `json:"latency"`
|
|
LatencyStr string `json:"latencyStr"`
|
|
LastSeen int64 `json:"lastSeen"`
|
|
LastSeenStr string `json:"lastSeenStr"`
|
|
Detail string `json:"detail"`
|
|
URL string `json:"url"`
|
|
Extra *HealthExtra `json:"extra,omitempty" extensions:"x-nullable"`
|
|
} // @name HealthJSON
|
|
|
|
HealthJSONRepr struct {
|
|
Name string
|
|
Config *HealthCheckConfig
|
|
Status HealthStatus
|
|
Started time.Time
|
|
Uptime time.Duration
|
|
Latency time.Duration
|
|
LastSeen time.Time
|
|
Detail string
|
|
URL *url.URL
|
|
Extra *HealthExtra
|
|
}
|
|
|
|
HealthExtra struct {
|
|
Config *LoadBalancerConfig `json:"config"`
|
|
Pool map[string]any `json:"pool"`
|
|
} // @name HealthExtra
|
|
)
|
|
|
|
const (
|
|
StatusUnknown HealthStatus = 0
|
|
StatusHealthy HealthStatus = (1 << iota)
|
|
StatusNapping
|
|
StatusStarting
|
|
StatusUnhealthy
|
|
StatusError
|
|
|
|
StatusUnknownStr = "unknown"
|
|
StatusHealthyStr = "healthy"
|
|
StatusNappingStr = "napping"
|
|
StatusStartingStr = "starting"
|
|
StatusUnhealthyStr = "unhealthy"
|
|
StatusErrorStr = "error"
|
|
|
|
NumStatuses int = iota - 1
|
|
|
|
HealthyMask = StatusHealthy | StatusNapping | StatusStarting
|
|
IdlingMask = StatusNapping | StatusStarting
|
|
)
|
|
|
|
var (
|
|
StatusHealthyStr2 = strconv.Itoa(int(StatusHealthy))
|
|
StatusNappingStr2 = strconv.Itoa(int(StatusNapping))
|
|
StatusStartingStr2 = strconv.Itoa(int(StatusStarting))
|
|
StatusUnhealthyStr2 = strconv.Itoa(int(StatusUnhealthy))
|
|
StatusErrorStr2 = strconv.Itoa(int(StatusError))
|
|
)
|
|
|
|
func NewHealthStatusFromString(s string) HealthStatus {
|
|
switch s {
|
|
case StatusHealthyStr, StatusHealthyStr2:
|
|
return StatusHealthy
|
|
case StatusUnhealthyStr, StatusUnhealthyStr2:
|
|
return StatusUnhealthy
|
|
case StatusNappingStr, StatusNappingStr2:
|
|
return StatusNapping
|
|
case StatusStartingStr, StatusStartingStr2:
|
|
return StatusStarting
|
|
case StatusErrorStr, StatusErrorStr2:
|
|
return StatusError
|
|
default:
|
|
return StatusUnknown
|
|
}
|
|
}
|
|
|
|
func (s HealthStatus) String() string {
|
|
switch s {
|
|
case StatusHealthy:
|
|
return StatusHealthyStr
|
|
case StatusUnhealthy:
|
|
return StatusUnhealthyStr
|
|
case StatusNapping:
|
|
return StatusNappingStr
|
|
case StatusStarting:
|
|
return StatusStartingStr
|
|
case StatusError:
|
|
return StatusErrorStr
|
|
default:
|
|
return StatusUnknownStr
|
|
}
|
|
}
|
|
|
|
func (s HealthStatus) Good() bool {
|
|
return s&HealthyMask != 0
|
|
}
|
|
|
|
func (s HealthStatus) Bad() bool {
|
|
return s&HealthyMask == 0
|
|
}
|
|
|
|
func (s HealthStatus) Idling() bool {
|
|
return s&IdlingMask != 0
|
|
}
|
|
|
|
func (s HealthStatus) MarshalJSON() ([]byte, error) {
|
|
return strconv.AppendQuote(nil, s.String()), nil
|
|
}
|
|
|
|
func (s *HealthStatus) UnmarshalJSON(data []byte) error {
|
|
var v string
|
|
if err := sonic.Unmarshal(data, &v); err != nil {
|
|
return fmt.Errorf("failed to unmarshal health status: %w", err)
|
|
}
|
|
|
|
*s = NewHealthStatusFromString(v)
|
|
return nil
|
|
}
|
|
|
|
func (jsonRepr *HealthJSONRepr) MarshalJSON() ([]byte, error) {
|
|
var url string
|
|
if jsonRepr.URL != nil {
|
|
url = jsonRepr.URL.String()
|
|
}
|
|
if url == "http://:0" {
|
|
url = ""
|
|
}
|
|
return sonic.Marshal(HealthJSON{
|
|
Name: jsonRepr.Name,
|
|
Config: jsonRepr.Config,
|
|
Started: jsonRepr.Started.Unix(),
|
|
StartedStr: strutils.FormatTime(jsonRepr.Started),
|
|
Status: jsonRepr.Status.String(),
|
|
Uptime: jsonRepr.Uptime.Seconds(),
|
|
UptimeStr: strutils.FormatDuration(jsonRepr.Uptime),
|
|
Latency: jsonRepr.Latency.Seconds(),
|
|
LatencyStr: strconv.Itoa(int(jsonRepr.Latency.Milliseconds())) + " ms",
|
|
LastSeen: jsonRepr.LastSeen.Unix(),
|
|
LastSeenStr: strutils.FormatLastSeen(jsonRepr.LastSeen),
|
|
Detail: jsonRepr.Detail,
|
|
URL: url,
|
|
Extra: jsonRepr.Extra,
|
|
})
|
|
}
|