Maint: healthcheck package interface rework

- return concrete struct type
- Add compilation checks for implementations
This commit is contained in:
Quentin McGaw (desktop)
2021-07-23 19:22:41 +00:00
parent c39ff5c233
commit 54610866f2
6 changed files with 64 additions and 54 deletions

View File

@@ -31,10 +31,10 @@ func (c *CLI) HealthCheck(ctx context.Context, env params.Env,
const timeout = 10 * time.Second
httpClient := &http.Client{Timeout: timeout}
healthchecker := healthcheck.NewChecker(httpClient)
client := healthcheck.NewClient(httpClient)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
url := "http://127.0.0.1:" + port
return healthchecker.Check(ctx, url)
return client.Check(ctx, url)
}

View File

@@ -12,26 +12,28 @@ var (
ErrHTTPStatusNotOK = errors.New("HTTP response status is not OK")
)
var _ Checker = (*Client)(nil)
type Checker interface {
Check(ctx context.Context, url string) error
}
type checker struct {
type Client struct {
httpClient *http.Client
}
func NewChecker(httpClient *http.Client) Checker {
return &checker{
func NewClient(httpClient *http.Client) *Client {
return &Client{
httpClient: httpClient,
}
}
func (h *checker) Check(ctx context.Context, url string) error {
func (c *Client) Check(ctx context.Context, url string) error {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return err
}
response, err := h.httpClient.Do(request)
response, err := c.httpClient.Do(request)
if err != nil {
return err
}

View File

@@ -9,7 +9,7 @@ import (
"time"
)
func (s *server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
func (s *Server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
defer close(done)
s.openvpn.healthyTimer = time.NewTimer(s.openvpn.healthyWait)

View File

@@ -5,9 +5,16 @@ import (
"time"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/openvpn"
)
func (s *server) onUnhealthyOpenvpn(ctx context.Context) {
type openvpnHealth struct {
looper openvpn.Looper
healthyWait time.Duration
healthyTimer *time.Timer
}
func (s *Server) onUnhealthyOpenvpn(ctx context.Context) {
s.logger.Info("program has been unhealthy for " +
s.openvpn.healthyWait.String() + ": restarting OpenVPN")
_, _ = s.openvpn.looper.ApplyStatus(ctx, constants.Stopped)

View File

@@ -0,0 +1,40 @@
package healthcheck
import (
"context"
"errors"
"net/http"
"time"
)
func (s *Server) Run(ctx context.Context, done chan<- struct{}) {
defer close(done)
loopDone := make(chan struct{})
go s.runHealthcheckLoop(ctx, loopDone)
server := http.Server{
Addr: s.config.ServerAddress,
Handler: s.handler,
}
serverDone := make(chan struct{})
go func() {
defer close(serverDone)
<-ctx.Done()
const shutdownGraceDuration = 2 * time.Second
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownGraceDuration)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
s.logger.Error("failed shutting down: " + err.Error())
}
}()
s.logger.Info("listening on " + s.config.ServerAddress)
err := server.ListenAndServe()
if err != nil && !errors.Is(ctx.Err(), context.Canceled) {
s.logger.Error(err.Error())
}
<-loopDone
<-serverDone
}

View File

@@ -2,21 +2,20 @@ package healthcheck
import (
"context"
"errors"
"net"
"net/http"
"time"
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/openvpn"
"github.com/qdm12/golibs/logging"
)
type Server interface {
var _ ServerRunner = (*Server)(nil)
type ServerRunner interface {
Run(ctx context.Context, done chan<- struct{})
}
type server struct {
type Server struct {
logger logging.Logger
handler *handler
resolver *net.Resolver
@@ -24,15 +23,9 @@ type server struct {
openvpn openvpnHealth
}
type openvpnHealth struct {
looper openvpn.Looper
healthyWait time.Duration
healthyTimer *time.Timer
}
func NewServer(config configuration.Health,
logger logging.Logger, openvpnLooper openvpn.Looper) Server {
return &server{
logger logging.Logger, openvpnLooper openvpn.Looper) *Server {
return &Server{
logger: logger,
handler: newHandler(logger),
resolver: net.DefaultResolver,
@@ -43,35 +36,3 @@ func NewServer(config configuration.Health,
},
}
}
func (s *server) Run(ctx context.Context, done chan<- struct{}) {
defer close(done)
loopDone := make(chan struct{})
go s.runHealthcheckLoop(ctx, loopDone)
server := http.Server{
Addr: s.config.ServerAddress,
Handler: s.handler,
}
serverDone := make(chan struct{})
go func() {
defer close(serverDone)
<-ctx.Done()
const shutdownGraceDuration = 2 * time.Second
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownGraceDuration)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
s.logger.Error("failed shutting down: " + err.Error())
}
}()
s.logger.Info("listening on " + s.config.ServerAddress)
err := server.ListenAndServe()
if err != nil && !errors.Is(ctx.Err(), context.Canceled) {
s.logger.Error(err.Error())
}
<-loopDone
<-serverDone
}