Skip to content

Commit

Permalink
feat: support pre health checks (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
nrwiersma authored Nov 15, 2023
1 parent aad13ef commit 7e48d80
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 6 deletions.
34 changes: 28 additions & 6 deletions http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,28 @@ func (s *Server) Close() error {
type HealthServerConfig struct {
Addr string
Handler http.Handler
Stats *statter.Statter
Log *logger.Logger

ReadyzChecks []healthz.HealthChecker
LivezChecks []healthz.HealthChecker

Stats *statter.Statter
Log *logger.Logger
}

// AddHealthzChecks adds the given checks to the config.
func (c *HealthServerConfig) AddHealthzChecks(checks ...healthz.HealthChecker) {
c.AddReadyzChecks(checks...)
c.AddLivezChecks(checks...)
}

// AddReadyzChecks adds the given checks to the config.
func (c *HealthServerConfig) AddReadyzChecks(checks ...healthz.HealthChecker) {
c.ReadyzChecks = append(c.ReadyzChecks, checks...)
}

// AddLivezChecks adds the given checks to the config.
func (c *HealthServerConfig) AddLivezChecks(checks ...healthz.HealthChecker) {
c.LivezChecks = append(c.LivezChecks, checks...)
}

// HealthServer is an HTTP server with healthz capabilities.
Expand All @@ -148,10 +168,12 @@ func NewHealthServer(ctx context.Context, cfg HealthServerConfig, opts ...SrvOpt
srv := NewServer(ctx, cfg.Addr, cfg.Handler, opts...)

return &HealthServer{
srv: srv,
shudownCh: make(chan struct{}),
stats: cfg.Stats,
log: cfg.Log,
srv: srv,
shudownCh: make(chan struct{}),
readyzChecks: cfg.ReadyzChecks,
livezChecks: cfg.LivezChecks,
stats: cfg.Stats,
log: cfg.Log,
}
}

Expand Down
49 changes: 49 additions & 0 deletions http/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,55 @@ func TestHealthServer(t *testing.T) {
assert.Equal(t, "+ test ok\nlivez check passed", body)
}

func TestHealthServer_WithPreChecks(t *testing.T) {
stats := statter.New(statter.DiscardReporter, time.Minute)
log := logger.New(io.Discard, logger.LogfmtFormat(), logger.Error)

lnCh := make(chan net.Listener, 1)
setTestHookServerServe(func(ln net.Listener) {
lnCh <- ln
})
t.Cleanup(func() { setTestHookServerServe(nil) })

check := healthz.NamedCheck("test", func(*http.Request) error {
return nil
})

cfg := &HealthServerConfig{
Addr: "localhost:0",
Handler: http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}),

Stats: stats,
Log: log,
}
cfg.AddHealthzChecks(check)

srv := NewHealthServer(context.Background(), *cfg)
srv.Serve(func(err error) {
require.NoError(t, err)
})
t.Cleanup(func() {
_ = srv.Close()
})

var ln net.Listener
select {
case <-time.After(30 * time.Second):
require.Fail(t, "Timed out waiting for server listener")
case ln = <-lnCh:
}

url := "http://" + ln.Addr().String() + "/readyz?verbose=1"
statusCode, body := requireDoRequest(t, url)
assert.Equal(t, statusCode, http.StatusOK)
assert.Equal(t, "+ test ok\n+ shutdown ok\nreadyz check passed", body)

url = "http://" + ln.Addr().String() + "/livez?verbose=1"
statusCode, body = requireDoRequest(t, url)
assert.Equal(t, statusCode, http.StatusOK)
assert.Equal(t, "+ test ok\nlivez check passed", body)
}

func TestHealthServer_ShutdownCausesReadyzCheckToFail(t *testing.T) {
stats := statter.New(statter.DiscardReporter, time.Minute)
log := logger.New(io.Discard, logger.LogfmtFormat(), logger.Error)
Expand Down

0 comments on commit 7e48d80

Please sign in to comment.