health

package
v1.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 16, 2024 License: MIT Imports: 9 Imported by: 6

README

health: Healthy Services

Build Status Go Reference

Overview

Package health provides a standard health check HTTP endpoint typically served under the /healthz and/or /livez paths.

The handler implementation iterates through a given list of service dependencies and respond with HTTP status 200 OK if all dependencies are healthy, 503 Service Unavailable otherwise. the response body lists each dependency with its status.

Healthy service example (using the httpie command line utility):

http http://localhost:8083/livez
HTTP/1.1 200 OK
Content-Length: 109
Content-Type: application/json
Date: Mon, 17 Jan 2022 23:23:12 GMT

{
    "status": {
        "ClickHouse": "OK",
        "poller": "OK"
    },
    "uptime": 20,
    "version": "91bb64a8103b494d0eac680f8e929e74882eea5f"
}

Unhealthy service:

http http://localhost:8083/livez
HTTP/1.1 503 Service Unavailable
Content-Length: 113
Content-Type: application/json
Date: Mon, 17 Jan 2022 23:23:20 GMT

{
    "status": {
        "ClickHouse": "OK",
        "poller": "NOT OK"
    },
    "uptime": 20,
    "version": "91bb64a8103b494d0eac680f8e929e74882eea5f"
}

Another Content-Type:

http http://localhost:8083/livez Accept:application/xml
HTTP/1.1 200 OK
Content-Length: 158
Content-Type: application/xml
Date: Thu, 07 Sep 2023 13:28:29 GMT

<health>
  <uptime>20</uptime>
  <version>91bb64a8103b494d0eac680f8e929e74882eea5f</version>
  <status>
    <ClickHouse>OK</ClickHouse>
    <poller>OK</poller>
  </status>
</health>

Usage

package main

import (
        "context"
        "database/sql"

        "goa.design/clue/health"
        "goa.design/clue/log"
        goahttp "goa.design/goa/v3/http"

        "github.com/repo/services/svc/clients/storage"
        httpsvrgen "github.com/repo/services/svc/gen/http/svc/server"
        svcgen "github.com/repo/services/svc/gen/svc"
)

func main() {
        // Initialize the log context
        ctx := log.With(log.Context(context.Background()), "svc", svcgen.ServiceName)

        // Create service clients used by this service
        // The client object must implement the `health.Pinger` interface
        // dsn := ...
        con, err := sql.Open("clickhouse", dsn)
        if err != nil {
                log.Error(ctx, "could not connect to clickhouse", "err", err.Error())
        }
        stc := storage.New(con)

        // Create the service (user code)
        svc := svc.New(ctx, stc)
        // Wrap the service with Goa endpoints
        endpoints := svcgen.NewEndpoints(svc)

        // Create HTTP server
        mux := goahttp.NewMuxer()
        httpsvr := httpsvrgen.New(endpoints, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, nil, nil)
        httpsvrgen.Mount(mux, httpsvr)

        // ** Mount health check handler **
        check := health.Handler(health.NewChecker(stc))
        mux.Handle("GET", "/healthz", check)
        mux.Handle("GET", "/livez", check)

        // ... start HTTP server
}

Creating an health check HTTP handler is as simple as:

  1. instantiating a health checker using the NewChecker function
  2. wrapping it in a HTTP handler using the Handler function

The NewChecker function accepts a list of dependencies to be checked that must implement by the Pinger interface.

// Pinger makes it possible to ping a downstream service.
Pinger interface {
        // Name of remote service.
        Name() string
        // Ping the remote service, return a non nil error if the
        // service is not available.
        Ping(context.Context) error
}

Implementing the Pinger Interface

For Downstream Microservices

The NewPinger function instantiates a Pinger for a service equipped with a /livez health check endpoint (e.g. a service exposing the handler created by this package Handler function).

For SQL Databases (e.g. PostgreSQL, ClickHouse)

The stdlib sql.DB type provides a PingContext method that can be used to ping a database. Implementing Pinger thus consists of adding the following two methods to the client struct:

// SQL database client used by service.
type client struct {
        db *sql.DB
}

// Ping implements the `health.Pinger` interface.
func (c *client) Ping(ctx context.Context) error {
        return c.db.PingContext(ctx)
}

// Name implements the `health.Pinger` interface.
func (c *client) Name() string {
        return "PostgreSQL" // ClickHouse, MySQL, etc.
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var StartedAt = time.Now()

StartedAt is the time the service was started.

View Source
var Version string

Version of service, initialized at compiled time.

Functions

func Handler

func Handler(chk Checker) http.HandlerFunc

Handler returns a HTTP handler that serves health check requests. The response body is the health status returned by chk.Check(). By default it's encoded as JSON, but you can specify a different encoding in the HTTP Accept header. The response status is 200 if chk.Check() returns a nil error, 503 otherwise.

Types

type Checker

type Checker interface {
	// Check that all dependencies are healthy. Check returns true
	// if the service is healthy. The returned Health struct
	// contains the health status of each dependency.
	Check(context.Context) (*Health, bool)
}

Checker exposes a health check.

func NewChecker

func NewChecker(deps ...Pinger) Checker

Create a Checker that checks the health of the given dependencies.

type Health

type Health struct {
	// Uptime of service in seconds.
	Uptime int64 `json:"uptime"`
	// Version of service.
	Version string `json:"version"`
	// Status of each dependency indexed by service name.
	// "OK" if dependency is healthy, "NOT OK" otherwise.
	Status map[string]string `json:"status,omitempty"`
}

Health status of a service.

func (Health) MarshalXML added in v0.19.0

func (h Health) MarshalXML(e *xml.Encoder, start xml.StartElement) error

type Option added in v0.2.0

type Option func(o *options)

Option configures a Pinger.

func WithPath added in v0.2.0

func WithPath(path string) Option

WithPath sets the path used to ping the service. Default path is "/livez".

func WithScheme added in v0.2.0

func WithScheme(scheme string) Option

WithScheme sets the scheme used to ping the service. Default scheme is "http".

type Pinger

type Pinger interface {
	// Name of remote service.
	Name() string
	// Ping the remote service, return a non nil error if the
	// service is not available.
	Ping(context.Context) error
}

Pinger makes it possible to ping a service.

func NewPinger

func NewPinger(name, addr string, opts ...Option) Pinger

NewPinger returns a new health-check client for the given service. It panics if the given host address is malformed. The default scheme is "http" and the default path is "/livez". Both can be overridden via options.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL