Merge pull request #3326 from mfaizanse/health_endpoint_params

Added param options to /healthz endpoint
This commit is contained in:
Ivan Kozlovic
2022-08-09 08:49:22 -06:00
committed by GitHub
5 changed files with 66 additions and 8 deletions

View File

@@ -875,8 +875,8 @@ func (s *Server) initEventTracking() {
s.zReq(c, reply, msg, &optz.EventFilterOptions, optz, func() (interface{}, error) { return s.Jsz(&optz.JSzOptions) })
},
"HEALTHZ": func(sub *subscription, c *client, _ *Account, subject, reply string, msg []byte) {
optz := &EventFilterOptions{}
s.zReq(c, reply, msg, optz, optz, func() (interface{}, error) { return s.healthz(), nil })
optz := &HealthzEventOptions{}
s.zReq(c, reply, msg, &optz.EventFilterOptions, optz, func() (interface{}, error) { return s.healthz(&optz.HealthzOptions), nil })
},
}
for name, req := range monSrvc {
@@ -1433,6 +1433,12 @@ type JszEventOptions struct {
EventFilterOptions
}
// In the context of system events, HealthzEventOptions are options passed to Healthz
type HealthzEventOptions struct {
HealthzOptions
EventFilterOptions
}
// returns true if the request does NOT apply to this server and can be ignored.
// DO NOT hold the server lock when
func (s *Server) filterRequest(fOpts *EventFilterOptions) bool {

View File

@@ -2170,6 +2170,8 @@ func TestServerEventsPingMonitorz(t *testing.T) {
{"JSZ", nil, &JSzOptions{}, []string{"now", "disabled"}},
{"HEALTHZ", nil, &JSzOptions{}, []string{"status"}},
{"HEALTHZ", &HealthzOptions{JSEnabled: true}, &JSzOptions{}, []string{"status"}},
{"HEALTHZ", &HealthzOptions{JSServerOnly: true}, &JSzOptions{}, []string{"status"}},
}
for i, test := range tests {

View File

@@ -1229,13 +1229,13 @@ func (c *cluster) waitOnServerHealthz(s *Server) {
c.t.Helper()
expires := time.Now().Add(30 * time.Second)
for time.Now().Before(expires) {
hs := s.healthz()
hs := s.healthz(nil)
if hs.Status == "ok" && hs.Error == _EMPTY_ {
return
}
time.Sleep(100 * time.Millisecond)
}
c.t.Fatalf("Expected server %q to eventually return healthz 'ok', but got %q", s, s.healthz().Error)
c.t.Fatalf("Expected server %q to eventually return healthz 'ok', but got %q", s, s.healthz(nil).Error)
}
func (c *cluster) waitOnServerCurrent(s *Server) {

View File

@@ -17129,7 +17129,7 @@ func TestJetStreamWorkQueueSourceRestart(t *testing.T) {
defer s.Shutdown()
checkFor(t, 10*time.Second, 200*time.Millisecond, func() error {
hs := s.healthz()
hs := s.healthz(nil)
if hs.Status == "ok" && hs.Error == _EMPTY_ {
return nil
}
@@ -17250,7 +17250,7 @@ func TestJetStreamWorkQueueSourceNamingRestart(t *testing.T) {
defer s.Shutdown()
checkFor(t, 10*time.Second, 200*time.Millisecond, func() error {
hs := s.healthz()
hs := s.healthz(nil)
if hs.Status == "ok" && hs.Error == _EMPTY_ {
return nil
}
@@ -17268,6 +17268,22 @@ func TestJetStreamWorkQueueSourceNamingRestart(t *testing.T) {
}
}
func TestJetStreamDisabledHealthz(t *testing.T) {
s := RunRandClientPortServer()
defer s.Shutdown()
if s.JetStreamEnabled() {
t.Fatalf("Expected JetStream to be disabled")
}
hs := s.healthz(&HealthzOptions{JSEnabled: true})
if hs.Status == "unavailable" && hs.Error == NewJSNotEnabledError().Error() {
return
}
t.Fatalf("Expected healthz to return error if JetStream is disabled, got status: %s", hs.Status)
}
func TestJetStreamPullMaxBytes(t *testing.T) {
s := RunBasicJetStreamServer()
if config := s.JetStreamConfig(); config != nil {

View File

@@ -2603,6 +2603,12 @@ type JSzOptions struct {
Limit int `json:"limit,omitempty"`
}
// HealthzOptions are options passed to Healthz
type HealthzOptions struct {
JSEnabled bool `json:"js-enabled,omitempty"`
JSServerOnly bool `json:"js-server-only,omitempty"`
}
type StreamDetail struct {
Name string `json:"name"`
Cluster *ClusterInfo `json:"cluster,omitempty"`
@@ -2928,7 +2934,19 @@ func (s *Server) HandleHealthz(w http.ResponseWriter, r *http.Request) {
s.httpReqStats[HealthzPath]++
s.mu.Unlock()
hs := s.healthz()
jsEnabled, err := decodeBool(w, r, "js-enabled")
if err != nil {
return
}
jsServerOnly, err := decodeBool(w, r, "js-server-only")
if err != nil {
return
}
hs := s.healthz(&HealthzOptions{
JSEnabled: jsEnabled,
JSServerOnly: jsServerOnly,
})
if hs.Error != _EMPTY_ {
s.Warnf("Healthcheck failed: %q", hs.Error)
w.WriteHeader(http.StatusServiceUnavailable)
@@ -2942,9 +2960,14 @@ func (s *Server) HandleHealthz(w http.ResponseWriter, r *http.Request) {
}
// Generate health status.
func (s *Server) healthz() *HealthStatus {
func (s *Server) healthz(opts *HealthzOptions) *HealthStatus {
var health = &HealthStatus{Status: "ok"}
// set option defaults
if opts == nil {
opts = &HealthzOptions{}
}
if err := s.readyForConnections(time.Millisecond); err != nil {
health.Status = "error"
health.Error = err.Error()
@@ -2954,6 +2977,12 @@ func (s *Server) healthz() *HealthStatus {
// Check JetStream
js := s.getJetStream()
if js == nil {
// If JetStream should be enabled then return error status.
if opts.JSEnabled {
health.Status = "unavailable"
health.Error = NewJSNotEnabledError().Error()
return health
}
return health
}
@@ -2985,6 +3014,11 @@ func (s *Server) healthz() *HealthStatus {
return health
}
// If JSServerOnly is true, then do not check further accounts, streams and consumers.
if opts.JSServerOnly {
return health
}
// Range across all accounts, the streams assigned to them, and the consumers.
// If they are assigned to this server check their status.
for acc, asa := range cc.streams {