An simple, easily extensible and concurrent health-check library for Go services

Healthcheck

Build Status Go Report Card GoDoc codecov FOSSA Status

A simple and extensible RESTful Healthcheck API implementation for Go services.

Health provides an http.Handlefunc for use as a healthcheck endpoint used by external services or load balancers. The function is used to determine the health of the application and to remove unhealthy application hosts or containers from rotation.

Instead of blindly returning a 200 HTTP status code, a healthcheck endpoint should test all the mandatory dependencies that are essential for proper functioning of a web service.

Implementing the Checker interface and passing it on to healthcheck allows you to test the the dependencies such as a database connection, caches, files and even external services you rely on. You may choose to not fail the healthcheck on failure of certain dependencies such as external services that you are not always dependent on.

Example

package main

import (
    "context"
    "database/sql"
    "net/http"
    "time"

    "github.com/etherlabsio/healthcheck"
    "github.com/etherlabsio/healthcheck/checkers"
    _ "github.com/go-sql-driver/mysql"
    "github.com/gorilla/mux"
)

func main() {
    // For brevity, error check is being omitted here.
    db, _ := sql.Open("mysql", "user:password@/dbname")
    defer db.Close()

    r := mux.NewRouter()
    r.Handle("/healthcheck", healthcheck.Handler(

        // WithTimeout allows you to set a max overall timeout.
        healthcheck.WithTimeout(5*time.Second),

        // Checkers fail the status in case of any error.
        healthcheck.WithChecker(
            "heartbeat", checkers.Heartbeat("$PROJECT_PATH/heartbeat"),
        ),

        healthcheck.WithChecker(
            "database", healthcheck.CheckerFunc(
                func(ctx context.Context) error {
                    return db.PingContext(ctx)
                },
            ),
        ),

        // Observers do not fail the status in case of error.
        healthcheck.WithObserver(
            "diskspace", checkers.DiskSpace("/var/log", 90),
        ),
    ))

    http.ListenAndServe(":8080", r)
}

Based on the example provided above, curl localhost:8080/healthcheck | jq should yield on error a response with an HTTP statusCode of 503.

{
  "status": "Service Unavailable",
  "errors": {
    "database": "dial tcp 127.0.0.1:3306: getsockopt: connection refused",
    "heartbeat": "heartbeat not found. application should be out of rotation"
  }
}

License

This project is licensed under the terms of the MIT license. See the LICENSE file.

FOSSA Status

Owner
Ether Labs
We envision, build, and scale inspired products.
Ether Labs
Comments
  • Proposal: Please start using Semantic Versioning

    Proposal: Please start using Semantic Versioning

    I found that this project already supports Go modules. But sadly, the tags doesn't follow Semantic Versioning, which means that all tags of this project will be ignored by Go modules and replaced by pseudo-versions, go get acts weirdly when tags are not in that form. It would be great to have the tagged release be named in the format vX.X.X format so that go mod can read it.

    	github.com/etherlabsio/healthcheck v0.0.0-20191224061800-dd3d2fd8c3f6
    

    Else the mod file shows something like github.com/etherlabsio/healthcheck v0.0.0-20191224061800-dd3d2fd8c3f6 which is not very readable and difficult to upgrade. It’s hard to verify which version is in use. This is not conducive to version control.

    So, I propose this project to follow Semantic Versioning in future versions. For example, v1.0.1, v2.0.0, v3.1.0-alpha, v3.1.0-beta.2etc, so that other project can use tag in go.mod.

  • Maintain overall max request timeout (Optional)

    Maintain overall max request timeout (Optional)

    Health Checks are called frequently, hence latency should ideally be low. Since most checks are to dependencies over the network, we need to make sure to timeout if the calls are not served within time.

    While it's the responsibility of each checker func to maintain it's own TTL, having a max timeout value for a health check request might be a good idea.

    This could be an optional feature.

  • Add license scan report and status

    Add license scan report and status

    Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.

    Below are docs for integrating FOSSA license checks into your CI:

  • Set default timeout to 30s

    Set default timeout to 30s

    It's better to set a safe timeout default rather than use the default value of 0. 30s might be too high for most health checks, and it has to be specific for every application.

  • Add option to not fail the healthcheck response for certain dependencies

    Add option to not fail the healthcheck response for certain dependencies

    By default, any error occurring in the checker responses leads to a 503 HTTP status code. But we may not want to fail the healthcheck in case certain dependencies fail (eg: metrics service, s3 etc) but would like to observe the errors in the response for taking further action.

  • Add a timeout option for healtcheck Handler

    Add a timeout option for healtcheck Handler

    Fixes #5 If we decide to export the private timeoutChecker introduced here, It could also solve checker specific timeouts. All one has to do is to wrap an existing timer with a timeout checker.

  • Coverage badges

    Coverage badges

    Added the coverage test to circleci artifacts. I believe that the badge in the markdown should pick this up once it is updated. Not sure as I have not really used circleci much.

    Resolves #11

  • Make the call to checkers concurrent.

    Make the call to checkers concurrent.

    Since Healthcheck usually checks dependencies present over the network there is a possibility of making multiple IO calls. Right now we are calling the check() function serially, so we'll wait till the function is returned. By using goroutines and waitgroup, we can make the calls more concurrent and hopefully reduce the overall latency of the healthcheck API.

    Since healthcheck API's are called frequently, lower latecy response time is imperative.

    PS: We'll also need to maintain an overall TTL for the healthcheck request. But that's a different issue to be addressed.

  • use request context in http handler

    use request context in http handler

    The handler uses context.Background() in the http handler. If the client (calling service) drop the connection, the processing will continue till an error occur when the handler tries to write a response.

  • go-routine leak when check times out

    go-routine leak when check times out

    If there is a time out before the checker is able to complete, then the goroutine started by the timeout checker forever waits to write on a channel.

    type timeoutChecker struct {
    	checker Checker
    }
    
    func (t *timeoutChecker) Check(ctx context.Context) error {
    	checkerChan := make(chan error)
    	go func() {
    		checkerChan <- t.checker.Check(ctx) // cannot write here to the channel, no reader
    	}()
    	select {
    	case err := <-checkerChan:
    		return err
    	case <-ctx.Done():
    		return errors.New("max check time exceeded")
    	}
    }
    

    Declaring the channel with size of 1 fixes the bug.

  • Maintain checker specific timeouts

    Maintain checker specific timeouts

    In addition to a common and overall timeout value defined for all health checkers, it'll be useful to override with a specific timeout value for a checker.

    Concern: My assumption is that it will be useful for smaller timeout values when compared to an overall timeout across all checkers, when we want to guarantee strict response times of the dependency.

    Does it even make sense to allow a higher value than the overall checker limit ? How would the implementation change.

A Simple HTTP health checker for golang

patsch Permanently Assert Target Succeeds Check Health use cases used by kubernetes cluster admins to quickly identify faulty ingresses used by kubern

Feb 22, 2022
⛑ Gatus - Automated service health dashboard
⛑ Gatus - Automated service health dashboard

A service health dashboard in Go that is meant to be used as a docker image with a custom configuration file. I personally deploy it in my Kubernetes

Dec 31, 2022
Track health of various dependencies - golang

Background This package helps setup health check based on status of external dependencies. The idea is to add all external dependencies like database,

Dec 17, 2021
Render health ECG (electrocardiogram) animation
Render health ECG (electrocardiogram) animation

HealthECG Render health ECG (electrocardiogram) animation About This program shows how the health ECG animation was implemented in the original Reside

Jan 6, 2022
Highly extensible, customizable application launcher and window switcher written in less than 300 lines of Golang and fyne
Highly extensible, customizable application launcher and window switcher written in less than 300 lines of Golang and fyne

golauncher A go application launcher A simple, highly extensible, customizable application launcher and window switcher written in less than 300 lines

Aug 21, 2022
Antch, a fast, powerful and extensible web crawling & scraping framework for Go

Antch Antch, inspired by Scrapy. If you're familiar with scrapy, you can quickly get started. Antch is a fast, powerful and extensible web crawling &

Jan 6, 2023
Package buildinfo provides basic building blocks and instructions to easily add build and release information to your app.
Package buildinfo provides basic building blocks and instructions to easily add build and release information to your app.

Package buildinfo provides basic building blocks and instructions to easily add build and release information to your app. This is done by replacing variables in main during build with ldflags.

Nov 14, 2021
Easily create & extract archives, and compress & decompress files of various formats

archiver Introducing Archiver 3.1 - a cross-platform, multi-format archive utility and Go library. A powerful and flexible library meets an elegant CL

Jan 7, 2023
Alfred 4 workflow to easily search and launch bookmarks from the Brave Browser

Alfred Brave Browser Bookmarks A simple and fast workflow for searching and launching Brave Browser bookmarks. Why this workflow? No python dependency

Nov 28, 2022
Go client library for Geonames Web Services (geonames.org)

geonames Go client library for Geonames Web Services (geonames.org) Usage Register your username at geonames.org Export ENV Var or read the username f

Nov 23, 2022
Tool to easily rename or move a bunch of files with a text editor of your choice
Tool to easily rename or move a bunch of files with a text editor of your choice

batch-rename With batch-rename you can utilize your favorite text editor to rename or move a bunch of files at once. It doesn't come with any features

Nov 2, 2022
A Github action to check if IDT could synthesize a given DNA sequence.

dna-is-synthesizable A github action to check if a part is synthesizable from a given Genbank file. dna-is-synthesizable is a Github Action that recei

Oct 28, 2021
Radiant is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services.

Radiant is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend services.

Mar 22, 2022
Scaffolding tool for golang based services

Scaffolding tool for golang based services

Mar 6, 2022
Robust services healthiness probing written in Go

Robust services healthiness probing written in Go. (with notification support of webhook, telegram and more)

Jun 20, 2022
Run The World. Command aggregator output. Define many services watch them in one place.

Run The World. Command aggregator output. Define many services watch them in one place.

Feb 2, 2022
A small API to be used in Traefik Forward Auth to block attacks on services behind your favorite web router

Dynamic IPs Blacklist for Traefik This small software implements the possibility to block access to all the services behind your Traefik service. The

Sep 2, 2022
Go Services for everyone :-)

Go Training Service Purpose The purpose of this project is to allow participants of the Go training sessions to have a hands-on experience, developing

Oct 29, 2022
This Go based project of Aadhyarupam Innovators demonstrate the code examples for building microservices, integration with cloud services (Google Cloud Firestore), application configuration management (Viper) etc.

This Go based project of Aadhyarupam Innovators demonstrate the code examples for building microservices, integration with cloud services (Google Cloud Firestore), application configuration management (Viper) etc.

Dec 22, 2022