-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from InVisionApp/feature/add-check-callback
Feature/add check callback
- Loading branch information
Showing
7 changed files
with
364 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
## Status Listener Example | ||
|
||
The `IStatusListener` interface allows you to hook into health check failures and recoveries as they occur. This example runs a dependency service, `dependency.go`, and a dependent service, `service.go`. | ||
|
||
The web server in `dependency.go` will return a `200` status code for 10 contiguous requests, then return `500` for 5 contiguous requests. The request cycle then resets. | ||
|
||
The web server in `service.go` uses go-health to check the dependency server. It also uses an implementation of `IStatusListener`, which includes functions | ||
|
||
* `HealthCheckFailed(entry *health.State)` | ||
* `HealthCheckRecovered(entry *health.State, recordedFailures int64, failureDurationSeconds float64)` | ||
|
||
The function `HealthCheckFailed` is triggered when the health check fails for the first time. A count of contiguous failures will be kept until the dependency recovers. Once the dependency does recover, the function `HealthCheckRecovered` is triggered, which reports how many healthchecks failed, as well as how long (in seconds) the dependency was in an unhealthy state. | ||
|
||
|
||
|
||
### To run example | ||
|
||
Within the project folder `/examples/status_listener/dependency`, run `go run dependency.go` on one terminal window, then from within `/examples/status_listener/service`, run `go run service.go` in another. You will observe the requests to the dependency, as well as the triggering and recovery of failed health checks. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"os" | ||
"sync" | ||
) | ||
|
||
// mischief | ||
type loki struct { | ||
sync.Mutex | ||
callcount int | ||
} | ||
|
||
// this is just a function that will return true | ||
// the last 5 out of every 15 times called | ||
func (l *loki) shouldBreakThings() bool { | ||
l.Lock() | ||
defer l.Unlock() | ||
l.callcount++ | ||
if l.callcount > 15 { | ||
l.callcount = 0 | ||
return false | ||
} | ||
if l.callcount > 10 { | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
var ( | ||
l *loki | ||
logger *log.Logger | ||
) | ||
|
||
func init() { | ||
l = &loki{} | ||
logger = log.New(os.Stderr, "dependency: ", 0) | ||
} | ||
|
||
func handleRequest(rw http.ResponseWriter, r *http.Request) { | ||
// ignore favicon | ||
if r.URL.Path == "/favicon.ico" { | ||
rw.WriteHeader(http.StatusOK) | ||
return | ||
} | ||
if l.shouldBreakThings() { | ||
logger.Print("👎") | ||
rw.WriteHeader(http.StatusInternalServerError) | ||
return | ||
} | ||
logger.Print("👍") | ||
rw.WriteHeader(http.StatusOK) | ||
return | ||
} | ||
|
||
func main() { | ||
http.HandleFunc("/", handleRequest) | ||
http.ListenAndServe("0.0.0.0:8081", nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"os" | ||
"time" | ||
|
||
"github.com/InVisionApp/go-health" | ||
"github.com/InVisionApp/go-health/checkers" | ||
"github.com/InVisionApp/go-health/handlers" | ||
) | ||
|
||
var svcLogger *log.Logger | ||
|
||
// HealthCheckStatusListener is the implementation of the IStatusListener interface | ||
type HealthCheckStatusListener struct{} | ||
|
||
// HealthCheckFailed is triggered when a health check fails the first time | ||
func (sl *HealthCheckStatusListener) HealthCheckFailed(entry *health.State) { | ||
svcLogger.Printf("State for failed health check: %+v", entry) | ||
} | ||
|
||
// HealthCheckRecovered is triggered when a health check recovers | ||
func (sl *HealthCheckStatusListener) HealthCheckRecovered(entry *health.State, recordedFailures int64, failureDurationSeconds float64) { | ||
svcLogger.Printf("Recovering from %d contiguous errors, lasting %1.2f seconds: %+v", recordedFailures, failureDurationSeconds, entry) | ||
} | ||
|
||
func init() { | ||
svcLogger = log.New(os.Stderr, "service: ", 0) | ||
} | ||
|
||
func main() { | ||
// Create a new health instance | ||
h := health.New() | ||
// disable logging from health lib | ||
h.DisableLogging() | ||
testURL, _ := url.Parse("http://0.0.0.0:8081") | ||
|
||
// Create a couple of checks | ||
httpCheck, _ := checkers.NewHTTP(&checkers.HTTPConfig{ | ||
URL: testURL, | ||
}) | ||
|
||
// Add the checks to the health instance | ||
h.AddChecks([]*health.Config{ | ||
{ | ||
Name: "dependency-check", | ||
Checker: httpCheck, | ||
Interval: time.Duration(2) * time.Second, | ||
Fatal: true, | ||
}, | ||
}) | ||
|
||
// set status listener | ||
sl := &HealthCheckStatusListener{} | ||
h.StatusListener = sl | ||
|
||
// Start the healthcheck process | ||
if err := h.Start(); err != nil { | ||
svcLogger.Fatalf("Unable to start healthcheck: %v", err) | ||
} | ||
|
||
svcLogger.Println("Server listening on :8080") | ||
|
||
// Define a healthcheck endpoint and use the built-in JSON handler | ||
http.HandleFunc("/healthcheck", handlers.NewJSONHandlerFunc(h, nil)) | ||
http.ListenAndServe(":8080", nil) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.