checkers

package
v1.0.3 Latest Latest
Warning

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

Go to latest
Published: Feb 10, 2018 License: MIT Imports: 13 Imported by: 0

README

checkers

The health library comes with a number of built-in checkers for well known types of dependencies.

If a pre-built checker is not available, you can create your own checkers by implementing the ICheckable interface (which consists of a single method - Status() (interface{}, error)).

If you do create a custom-checker - consider opening a PR and adding it to the list of built-in checkers.

Built-in checkers

HTTP

The HTTP checker is a generic HTTP call executor. To make use of it, instantiate and fill out a HTTPConfig struct and pass it into checkers.NewHTTP(...).

The only required attribute is HTTPConfig.URL (*url.URL). Refer to the source code for all available attributes on the struct.

Redis

The Redis checker allows you to test that your server is either available (by ping), is able to set a value, is able to get a value or all of the above.

To make use of it, instantiate and fill out a RedisConfig struct and pass it to checkers.NewRedis(...).

The RedisConfig must contain a valid RedisAuthConfig and at least one check method (ping, set or get).

Refer to the godocs for additional info.

SQL DB

The SQL DB checker has implementations for the following interfaces:

  • SQLPinger, which encloses PingContext in sql.DB and sql.Conn

  • SQLQueryer, which encloses QueryContext in sql.DB, sql.Conn, sql.Stmt, and sql.Tx

  • SQLExecer, which encloses ExecContext in sql.DB, sql.Conn, sql.Stmt, and sql.Tx

    SQLConfig

    The SQLConfig struct is required when using the SQL DB health check. It must contain an inplementation of one of either SQLPinger, SQLQueryer, or SQLExecer.

    If SQLQueryer or SQLExecer are implemented, then Query must be valid (len > 0).

    Additionally, if SQLQueryer or SQLExecer are implemented, you have the option to also set either the QueryerResultHandler or ExecerResultHandler functions. These functions allow you to evaluate the result of a query or exec operation. If you choose not to implement these yourself, the default handlers are used.

    The default ExecerResultHandler is successful if the passed exec operation affected one and only one row.

    The default QueryerResultHandler is successful if the passed query operation returned one and only one row.

    SQLPinger

    Use the SQLPinger interface if your health check is only concerned with your application's database connectivity. All you need to do is set the Pinger value in your SQLConfig.

    db, err := sql.Open("mysql", dsn)
    if err != nil {
    	return err
    }
    
    sqlCheck, err := checkers.NewSQL(&checkers.SQLConfig{
    	Pinger: db
    })
    if err != nil {
    	return err
    }
    
    hc := health.New()
    healthCheck.AddCheck(&health.Config{
    	Name:     "sql-check",
    	Checker:  sqlCheck,
    	Interval: time.Duration(3) * time.Second,
    	Fatal:    true,
    })
    
    SQLQueryer

    Use the SQLQueryer interface if your health check requires you to read rows from your database. You can optionally supply a query result handler function. If you don't supply one, the default function will be used. The function signature for the handler is:

    type SQLQueryerResultHandler func(rows *sql.Rows) (bool, error)
    

    The default query handler returns true if there was exactly one row in the resultset:

    func DefaultQueryHandler(rows *sql.Rows) (bool, error) {
    	defer rows.Close()
    
    	numRows := 0
    	for rows.Next() {
    		numRows++
    	}
    
    	return numRows == 1, nil
    }
    

    IMPORTANT: Note that your query handler is responsible for closing the passed *sql.Rows value.

    Sample SQLQueryer implementation:

    // this is our custom query row handler
    func myQueryHandler(rows *sql.Rows) (bool, error) {
    	defer rows.Close()
    
    	var healthValue string
    	for rows.Next() {
    		// this query will ever return at most one row
    		if err := rows.Scan(&healthValue); err != nil {
    			return false, err
    		}
    	}
    
    	return healthValue == "ok", nil
    }
    
    db, err := sql.Open("mysql", dsn)
    if err != nil {
    	return err
    }
    
    // we pass the id we are looking for inside the params value
    sqlCheck, err := checkers.NewSQL(&checkers.SQLConfig{
    	Queryerer:            db,
    	Query:                "SELECT healthValue FROM some_table WHERE id = ?",
    	Params:               []interface{}{1},
    	QueryerResultHandler: myQueryHandler
    })
    if err != nil {
    	return err
    }
    
    hc := health.New()
    healthCheck.AddCheck(&health.Config{
    	Name:     "sql-check",
    	Checker:  sqlCheck,
    	Interval: time.Duration(3) * time.Second,
    	Fatal:    true,
    })
    
    SQLExecer

    Use the SQLExecer interface if your health check requires you to update or insert to your database. You can optionally supply an exec result handler function. If you don't supply one, the default function will be used. The function signature for the handler is:

    type SQLExecerResultHandler func(result sql.Result) (bool, error)
    

    The default exec handler returns true if there was exactly one affected row:

    func DefaultExecHandler(result sql.Result) (bool, error) {
    	affectedRows, err := result.RowsAffected()
    	if err != nil {
    		return false, err
    	}
    
    	return affectedRows == int64(1), nil
    }
    

    Sample SQLExecer implementation:

    // this is our custom exec result handler
    func myExecHandler(result sql.Result) (bool, error) {
    	insertId, err := result.LastInsertId()
    	if err != nil {
    		return false, err
    	}
    
    	// for this example, a check isn't valid 
    	// until after the 100th iteration
    	return insertId > int64(100), nil
    }
    
    db, err := sql.Open("mysql", dsn)
    if err != nil {
    	return err
    }
    
    sqlCheck, err := checkers.NewSQL(&checkers.SQLConfig{
    	Execer:              db,
    	Query:               "INSERT INTO checks (checkTS) VALUES (NOW())",
    	ExecerResultHandler: myExecHandler
    })
    if err != nil {
    	return err
    }
    
    hc := health.New()
    healthCheck.AddCheck(&health.Config{
    	Name:     "sql-check",
    	Checker:  sqlCheck,
    	Interval: time.Duration(3) * time.Second,
    	Fatal:    true,
    })
    
Mongo

Planned, but PR's welcome!

Documentation

Index

Constants

View Source
const (
	// RedisDefaultSetValue will be used if the "Set" check method is enabled
	// and "RedisSetOptions.Value" is _not_ set.
	RedisDefaultSetValue = "go-health/redis-check"
)

Variables

This section is empty.

Functions

func DefaultExecHandler added in v1.0.2

func DefaultExecHandler(result sql.Result) (bool, error)

DefaultExecHandler is the default SQLExecer result handler that assumes one row was affected in the passed query

func DefaultQueryHandler added in v1.0.2

func DefaultQueryHandler(rows *sql.Rows) (bool, error)

DefaultQueryHandler is the default SQLQueryer result handler that assumes one row was returned from the passed query

Types

type HTTP

type HTTP struct {
	Config *HTTPConfig
}

HTTP implements the "ICheckable" interface.

func NewHTTP

func NewHTTP(cfg *HTTPConfig) (*HTTP, error)

NewHTTP creates a new HTTP checker that can be used for ".AddCheck(s)".

func (*HTTP) Status

func (h *HTTP) Status() (interface{}, error)

Status is used for performing an HTTP check against a dependency; it satisfies the "ICheckable" interface.

type HTTPConfig

type HTTPConfig struct {
	URL        *url.URL      // Required
	Method     string        // Optional (default GET)
	Payload    interface{}   // Optional
	StatusCode int           // Optional (default 200)
	Expect     string        // Optional
	Client     *http.Client  // Optional
	Timeout    time.Duration // Optional (default 3s)
}

HTTPConfig is used for configuring an HTTP check. The only required field is `URL`.

"Method" is optional and defaults to `GET` if undefined.

"Payload" is optional and can accept `string`, `[]byte` or will attempt to marshal the input to JSON for use w/ `bytes.NewReader()`.

"StatusCode" is optional and defaults to `200`.

"Expect" is optional; if defined, operates as a basic "body should contain <string>".

"Client" is optional; if undefined, a new client will be created using "Timeout".

"Timeout" is optional and defaults to "3s".

type Redis

type Redis struct {
	Config *RedisConfig
	// contains filtered or unexported fields
}

Redis implements the ICheckable interface

func NewRedis

func NewRedis(cfg *RedisConfig) (*Redis, error)

NewRedis creates a new "go-redis/redis" checker that can be used w/ "AddChecks()".

func (*Redis) Status

func (r *Redis) Status() (interface{}, error)

Status is used for performing a redis check against a dependency; it satisfies the "ICheckable" interface.

type RedisAuthConfig

type RedisAuthConfig struct {
	Addr     string // `host:port` format
	Password string // leave blank if no password
	DB       int    // leave unset if no specific db
}

RedisAuthConfig defines how to connect to redis.

type RedisConfig

type RedisConfig struct {
	Auth *RedisAuthConfig
	Ping bool
	Set  *RedisSetOptions
	Get  *RedisGetOptions
}

RedisConfig is used for configuring the go-redis check.

"Auth" is _required_; redis connection/auth config.

"Ping" is optional; the most basic check method, performs a `.Ping()` on the client.

"Get" is optional; perform a "GET" on a key; refer to the "RedisGetOptions" docs for details.

"Set" is optional; perform a "SET" on a key; refer to the "RedisSetOptions" docs for details.

Note: At least _one_ check method must be set/enabled; you can also enable _all_ of the check methods (ie. perform a ping, set this key and now try to retrieve that key).

type RedisGetOptions

type RedisGetOptions struct {
	Key               string
	Expect            string
	NoErrorMissingKey bool
}

RedisGetOptions contains attributes that can alter the behavior of the redis "GET" check.

"Key" is _required_; the name of the key that we are attempting to "GET".

"Expect" is optional; optionally verify that the value for the key matches the Expect value.

"NoErrorMissingKey" is optional; by default, the "GET" check will error if the key we are fetching does not exist; flip this bool if that is normal/expected/ok.

type RedisSetOptions

type RedisSetOptions struct {
	Key        string
	Value      string
	Expiration time.Duration
}

RedisSetOptions contains attributes that can alter the behavior of the redis "SET" check.

"Key" is _required_; the name of the key we are attempting to "SET".

"Value" is optional; what the value should hold; if not set, it will be set to "RedisDefaultSetValue".

"Expiration" is optional; if set, a TTL will be attached to the key.

type SQL added in v1.0.2

type SQL struct {
	Config *SQLConfig
}

SQL implements the "ICheckable" interface

func NewSQL added in v1.0.2

func NewSQL(cfg *SQLConfig) (*SQL, error)

NewSQL creates a new database checker that can be used for ".AddCheck(s)".

func (*SQL) Status added in v1.0.2

func (s *SQL) Status() (interface{}, error)

Status is used for performing a database ping against a dependency; it satisfies the "ICheckable" interface.

type SQLConfig added in v1.0.2

type SQLConfig struct {
	// Pinger is the value implementing SQLPinger
	Pinger SQLPinger

	// Queryer is the value implementing SQLQueryer
	Queryer SQLQueryer

	// Execer is the value implementing SQLExecer
	Execer SQLExecer

	// Query is the parameterized SQL query required
	// with both Queryer and Execer
	Query string

	// Params are the SQL query parameters, if any
	Params []interface{}

	// QueryerResultHandler handles the result of
	// the QueryContext function
	QueryerResultHandler SQLQueryerResultHandler

	// ExecerResultHandler handles the result of
	// the ExecContext function
	ExecerResultHandler SQLExecerResultHandler
}

SQLConfig is used for configuring a database check. One of the Pinger, Queryer, or Execer fields is required.

If Execer is set, it will take precedence over Queryer and Pinger, Execer implements the SQLExecer interface in this package. The sql.DB and sql.TX structs both implement this interface.

Note that if the Execer is set, then the ExecerResultHandler and Query values MUST also be set

If Queryer is set, it will take precedence over Pinger. SQLQueryer implements the SQLQueryer interface in this package. The sql.DB and sql.TX structs both implement this interface.

Note that if the Queryer is set, then the QueryerResultHandler and Query values MUST also be set

Pinger implements the SQLPinger interface in this package. The sql.DB struct implements this interface.

type SQLExecer added in v1.0.2

type SQLExecer interface {
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
}

SQLExecer is an interface that allows executing of queries in the database

type SQLExecerResultHandler added in v1.0.2

type SQLExecerResultHandler func(result sql.Result) (bool, error)

SQLExecerResultHandler is the BYO function to handle a database exec result

type SQLPinger added in v1.0.2

type SQLPinger interface {
	PingContext(ctx context.Context) error
}

SQLPinger is an interface that allows direct pinging of the database

type SQLQueryer added in v1.0.2

type SQLQueryer interface {
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
}

SQLQueryer is an interface that allows querying of the database

type SQLQueryerResultHandler added in v1.0.2

type SQLQueryerResultHandler func(rows *sql.Rows) (bool, error)

SQLQueryerResultHandler is the BYO function to handle the result of an SQL SELECT query

Jump to

Keyboard shortcuts

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