Skip to content

Commit

Permalink
Merge pull request #19 from hellofresh/feature-improvements
Browse files Browse the repository at this point in the history
Check improvements
  • Loading branch information
aleksandrzhiliaev authored Jul 26, 2018
2 parents 7074f86 + c278f80 commit 456ffac
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 220 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ before_install:

install:
- mkdir -p $GOPATH/bin
- make deps

script:
- make all
Expand Down
16 changes: 7 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
OK_COLOR=\033[32;01m
NO_COLOR=\033[0m

all: deps lint test checks
all: deps lint test

lint:
@echo "$(OK_COLOR)==> Linting... $(NO_COLOR)"
@go vet ./...

test:
@go test -v -cover ./...

deps:
@echo "$(OK_COLOR)==> Installing dependencies $(NO_COLOR)"
@go get -u gopkg.in/mgo.v2
Expand All @@ -18,15 +15,16 @@ deps:
@go get -u github.com/streadway/amqp
@go get -u github.com/garyburd/redigo/redis

checks:
test:
@echo "$(OK_COLOR)==> Running tests against container deps $(NO_COLOR)"
@docker-compose up -d
@sleep 3
@echo "$(OK_COLOR)==> Running checks tests against container deps $(NO_COLOR)" && \
@sleep 3 && \
HEALTH_GO_PG_DSN="postgres://test:test@`docker-compose port postgres 5432`/test?sslmode=disable" \
HEALTH_GO_MQ_DSN="amqp://guest:guest@`docker-compose port rabbit 5672`/" \
HEALTH_GO_RD_DSN="redis://`docker-compose port redis 6379`/" \
HEALTH_GO_MG_DSN="`docker-compose port mongo 27017`/" \
HEALTH_GO_MS_DSN="test:test@tcp(`docker-compose port mysql 3306`)/test?charset=utf8" \
go test -v -cover ./...
HEALTH_GO_HTTP_URL="http://`docker-compose port http 80`/status" \
go test -cover ./...

.PHONY: all deps test lint checks
.PHONY: all deps test lint
32 changes: 5 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# health-go
[![Build Status](https://travis-ci.com/hellofresh/health-go.svg?branch=master)](https://travis-ci.com/hellofresh/health-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/hellofresh/health-go)](https://goreportcard.com/report/github.com/hellofresh/health-go)
[![Go Doc](https://godoc.org/github.com/hellofresh/health-go?status.svg)](https://godoc.org/github.com/hellofresh/health-go)

* Exposes an HTTP handler that retrieves health status of the application
* Implements some generic checkers for the following services:
Expand Down Expand Up @@ -49,16 +51,7 @@ func main() {
Timeout: time.Second * 2,
SkipOnErr: false,
Check: healthMysql.New(healthMysql.Config{
DSN: "test:test@tcp(0.0.0.0:31726)/test?charset=utf8",,
Table: "health_check",
IDColumn: "id",
InsertColumnsFunc: func() map[string]interface{} {
return map[string]interface{}{
"secret": time.Now().Unix(),
"extra": time.Now().Unix(),
"redirect_uri": "http://localhost",
}
},
DSN: "test:test@tcp(0.0.0.0:31726)/test?charset=utf8",
},
})

Expand Down Expand Up @@ -87,7 +80,7 @@ func main() {
SkipOnErr: true,
Check: func() error {
// rabbitmq health check implementation goes here
},
}),
})

health.Register(health.Config{
Expand All @@ -103,15 +96,6 @@ func main() {
SkipOnErr: false,
Check: healthMysql.New(healthMysql.Config{
DSN: "test:test@tcp(0.0.0.0:31726)/test?charset=utf8",
Table: "health_check",
IDColumn: "id",
InsertColumnsFunc: func() map[string]interface{} {
return map[string]interface{}{
"secret": time.Now().Unix(),
"extra": time.Now().Unix(),
"redirect_uri": "http://localhost",
}
},
},
})

Expand All @@ -121,6 +105,7 @@ func main() {
}
```

For more examples please check [here](https://github.com/hellofresh/health-go/blob/master/_examples/server.go)
## API Documentation

### `GET /status`
Expand Down Expand Up @@ -192,13 +177,6 @@ HTTP/1.1 503 Service Unavailable
- Push to the branch (`git push origin my-new-feature`)
- Create new Pull Request

## Badges

[![Build Status](https://travis-ci.org/hellofresh/health-go.svg?branch=master)](https://travis-ci.org/hellofresh/health-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/hellofresh/health-go)](https://goreportcard.com/report/github.com/hellofresh/health-go)
[![Go Doc](https://godoc.org/github.com/hellofresh/health-go?status.svg)](https://godoc.org/github.com/hellofresh/health-go)

---

> GitHub [@hellofresh](https://github.com/hellofresh)  · 
> Medium [@engineering.hellofresh](https://engineering.hellofresh.com)
41 changes: 38 additions & 3 deletions _examples/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,56 @@ import (
"time"

"github.com/hellofresh/health-go"
healthHttp "github.com/hellofresh/health-go/checks/http"
healthMySql "github.com/hellofresh/health-go/checks/mysql"
healthPg "github.com/hellofresh/health-go/checks/postgres"
)

func main() {
// custom health check example (fail)
health.Register(health.Config{
Name: "rabbitmq",
Name: "some-custom-check-fail",
Timeout: time.Second * 5,
SkipOnErr: true,
Check: func() error { return errors.New("Failed duriung rabbitmq health check") },
Check: func() error { return errors.New("failed during rabbitmq health check") },
})

// custom health check example (success)
health.Register(health.Config{
Name: "mongodb",
Name: "some-custom-check-success",
Check: func() error { return nil },
})

// http health check example
health.Register(health.Config{
Name: "http-check",
Timeout: time.Second * 5,
SkipOnErr: true,
Check: healthHttp.New(healthHttp.Config{
URL: `http://example.com`,
}),
})

// postgres health check example
health.Register(health.Config{
Name: "postgres-check",
Timeout: time.Second * 5,
SkipOnErr: true,
Check: healthPg.New(healthPg.Config{
DSN: `postgres://test:[email protected]:32807/test?sslmode=disable`,
}),
})

// mysql health check example
health.Register(health.Config{
Name: "mysql-check",
Timeout: time.Second * 5,
SkipOnErr: true,
Check: healthMySql.New(healthMySql.Config{
DSN: `test:test@tcp(0.0.0.0:32802)/test?charset=utf8`,
}),
})

http.Handle("/status", health.Handler())
http.ListenAndServe(":3000", nil)
}
22 changes: 22 additions & 0 deletions checks/http/check_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package http

import (
"os"
"testing"
)

const httpURLEnv = "HEALTH_GO_HTTP_URL"

func TestNew(t *testing.T) {
if os.Getenv(httpURLEnv) == "" {
t.SkipNow()
}

check := New(Config{
URL: os.Getenv(httpURLEnv),
})

if err := check(); err != nil {
t.Fatalf("HTTP check failed: %s", err.Error())
}
}
91 changes: 10 additions & 81 deletions checks/mysql/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package mysql

import (
"database/sql"
"fmt"
"strings"
"errors"

// MySQL database driver
_ "github.com/go-sql-driver/mysql"
Expand All @@ -15,27 +12,15 @@ type Config struct {
// DSN is the MySQL instance connection DSN. Required.
DSN string

// Table is the table name used for testing, must already exist in the DB and
// has insert/select/delete privileges for the connection user. Required.
Table string

// IDColumn is the primary column for the table used for testing. Required.
IDColumn string

// InsertColumnsFunc is the callback function that returns map[<column>]<value>
// for testing insert operation. Required.
InsertColumnsFunc func() map[string]interface{}

// LogFunc is the callback function for errors logging during check.
// If not set logging is skipped.
LogFunc func(err error, details string, extra ...interface{})
}

// New creates new MySQL health check that verifies the following:
// - connection establishing
// - inserting a row into defined table
// - selecting inserted row
// - deleting inserted row
// - doing the ping command
// - selecting mysql version
func New(config Config) func() error {
if config.LogFunc == nil {
config.LogFunc = func(err error, details string, extra ...interface{}) {}
Expand All @@ -48,80 +33,24 @@ func New(config Config) func() error {
return err
}

columns := config.InsertColumnsFunc()
columnNames := []string{}
columnPlaceholders := []string{}
columnValues := []interface{}{}
i := 1
for column, value := range columns {
columnNames = append(columnNames, column)
columnPlaceholders = append(columnPlaceholders, "?")
columnValues = append(columnValues, value)

i++
}

insertQuery := fmt.Sprintf(
"INSERT INTO %s (%s) VALUES (%s)",
config.Table,
strings.Join(columnNames, ", "),
strings.Join(columnPlaceholders, ", "),
)
defer func() {
if err = db.Close(); err != nil {
config.LogFunc(err, "MySQL health check failed during connection closing")
}
}()

result, err := db.Exec(insertQuery, columnValues...)
err = db.Ping()
if err != nil {
config.LogFunc(err, "MySQL health check failed during insert")
config.LogFunc(err, "MySQL health check failed during ping")
return err
}

idValue, err := result.LastInsertId()
if err != nil {
config.LogFunc(err, "MySQL health check failed during retrieval of last inserted id")
return err
}

selectQuery := fmt.Sprintf(
"SELECT %s FROM %s WHERE %s = ?",
strings.Join(columnNames, ", "),
config.Table,
config.IDColumn,
)
selectRows, err := db.Query(selectQuery, idValue)
_, err = db.Query(`SELECT VERSION()`)
if err != nil {
config.LogFunc(err, "MySQL health check failed during select")
return err
}

if !selectRows.Next() {
config.LogFunc(err, "MySQL health check failed during checking select result rows")
return errors.New("looks like select result has 0 rows")
}
err = selectRows.Close()
if err != nil {
config.LogFunc(err, "MySQL health check failed during closing select result")
return err
}

deleteQuery := fmt.Sprintf(
"DELETE FROM %s WHERE %s = ?",
config.Table,
config.IDColumn,
)
deleteResult, err := db.Exec(deleteQuery, idValue)
if err != nil {
config.LogFunc(err, "MySQL health check failed during delete")
return err
}
deleted, err := deleteResult.RowsAffected()
if err != nil {
config.LogFunc(err, "MySQL health check failed during extracting delete result")
return err
}
if deleted < 1 {
config.LogFunc(err, "MySQL health check failed during checking delete result")
return errors.New("looks like delete removed 0 rows")
}

return nil
}
}
12 changes: 1 addition & 11 deletions checks/mysql/check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package mysql
import (
"os"
"testing"
"time"
)

const mysqlDSNEnv = "HEALTH_GO_MS_DSN"
Expand All @@ -14,16 +13,7 @@ func TestNew(t *testing.T) {
}

check := New(Config{
DSN: os.Getenv(mysqlDSNEnv),
Table: "test",
IDColumn: "id",
InsertColumnsFunc: func() map[string]interface{} {
return map[string]interface{}{
"secret": time.Now().Format(time.RFC3339Nano),
"extra": time.Now().Format(time.RFC3339Nano),
"redirect_uri": "http://localhost",
}
},
DSN: os.Getenv(mysqlDSNEnv),
})

if err := check(); err != nil {
Expand Down
Loading

0 comments on commit 456ffac

Please sign in to comment.