Add a TCP health checker
Also, add timeout and status code parameters to the HTTP checker, and remove the threshold parameter for the file checker. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
b9b9cafa8f
commit
e8f088fea6
6 changed files with 279 additions and 46 deletions
|
@ -181,9 +181,9 @@ type MailOptions struct {
|
||||||
To []string `yaml:"to,omitempty"`
|
To []string `yaml:"to,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileChecker is a type of entry in the checkers section for checking files
|
// FileChecker is a type of entry in the health section for checking files.
|
||||||
type FileChecker struct {
|
type FileChecker struct {
|
||||||
// Interval is the number of seconds in between checks
|
// Interval is the duration in between checks
|
||||||
Interval time.Duration `yaml:"interval,omitempty"`
|
Interval time.Duration `yaml:"interval,omitempty"`
|
||||||
// File is the path to check
|
// File is the path to check
|
||||||
File string `yaml:"file,omitempty"`
|
File string `yaml:"file,omitempty"`
|
||||||
|
@ -192,10 +192,13 @@ type FileChecker struct {
|
||||||
Threshold int `yaml:"threshold,omitempty"`
|
Threshold int `yaml:"threshold,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPChecker is a type of entry in the checkers section for checking HTTP
|
// HTTPChecker is a type of entry in the health section for checking HTTP URIs.
|
||||||
// URIs
|
|
||||||
type HTTPChecker struct {
|
type HTTPChecker struct {
|
||||||
// Interval is the number of seconds in between checks
|
// Timeout is the duration to wait before timing out the HTTP request
|
||||||
|
Timeout time.Duration `yaml:"interval,omitempty"`
|
||||||
|
// StatusCode is the expected status code
|
||||||
|
StatusCode int
|
||||||
|
// Interval is the duration in between checks
|
||||||
Interval time.Duration `yaml:"interval,omitempty"`
|
Interval time.Duration `yaml:"interval,omitempty"`
|
||||||
// URI is the HTTP URI to check
|
// URI is the HTTP URI to check
|
||||||
URI string `yaml:"uri,omitempty"`
|
URI string `yaml:"uri,omitempty"`
|
||||||
|
@ -204,18 +207,33 @@ type HTTPChecker struct {
|
||||||
Threshold int `yaml:"threshold,omitempty"`
|
Threshold int `yaml:"threshold,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPChecker is a type of entry in the health section for checking TCP servers.
|
||||||
|
type TCPChecker struct {
|
||||||
|
// Timeout is the duration to wait before timing out the TCP connection
|
||||||
|
Timeout time.Duration `yaml:"interval,omitempty"`
|
||||||
|
// Interval is the duration in between checks
|
||||||
|
Interval time.Duration `yaml:"interval,omitempty"`
|
||||||
|
// Addr is the TCP address to check
|
||||||
|
Addr string `yaml:"addr,omitempty"`
|
||||||
|
// Threshold is the number of times a check must fail to trigger an
|
||||||
|
// unhealthy state
|
||||||
|
Threshold int `yaml:"threshold,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Health provides the configuration section for health checks.
|
// Health provides the configuration section for health checks.
|
||||||
type Health struct {
|
type Health struct {
|
||||||
// FileChecker is a list of paths to check
|
// FileCheckers is a list of paths to check
|
||||||
FileCheckers []FileChecker `yaml:"file,omitempty"`
|
FileCheckers []FileChecker `yaml:"file,omitempty"`
|
||||||
// HTTPChecker is a list of URIs to check
|
// HTTPCheckers is a list of URIs to check
|
||||||
HTTPCheckers []HTTPChecker `yaml:"http,omitempty"`
|
HTTPCheckers []HTTPChecker `yaml:"http,omitempty"`
|
||||||
|
// TCPCheckers is a list of URIs to check
|
||||||
|
TCPCheckers []TCPChecker `yaml:"tcp,omitempty"`
|
||||||
// StorageDriver configures a health check on the configured storage
|
// StorageDriver configures a health check on the configured storage
|
||||||
// driver
|
// driver
|
||||||
StorageDriver struct {
|
StorageDriver struct {
|
||||||
// Enabled turns on the health check for the storage driver
|
// Enabled turns on the health check for the storage driver
|
||||||
Enabled bool `yaml:"enabled,omitempty"`
|
Enabled bool `yaml:"enabled,omitempty"`
|
||||||
// Interval is the number of seconds in between checks
|
// Interval is the duration in between checks
|
||||||
Interval time.Duration `yaml:"interval,omitempty"`
|
Interval time.Duration `yaml:"interval,omitempty"`
|
||||||
// Threshold is the number of times a check must fail to trigger an
|
// Threshold is the number of times a check must fail to trigger an
|
||||||
// unhealthy state
|
// unhealthy state
|
||||||
|
|
|
@ -203,9 +203,15 @@ information about each option that appears later in this page.
|
||||||
file:
|
file:
|
||||||
- file: /path/to/checked/file
|
- file: /path/to/checked/file
|
||||||
interval: 10s
|
interval: 10s
|
||||||
threshold: 3
|
|
||||||
http:
|
http:
|
||||||
- uri: http://server.to.check/must/return/200
|
- uri: http://server.to.check/must/return/200
|
||||||
|
statuscode: 200
|
||||||
|
timeout: 3s
|
||||||
|
interval: 10s
|
||||||
|
threshold: 3
|
||||||
|
tcp:
|
||||||
|
- addr: redis-server.domain.com:6379
|
||||||
|
timeout: 3s
|
||||||
interval: 10s
|
interval: 10s
|
||||||
threshold: 3
|
threshold: 3
|
||||||
|
|
||||||
|
@ -1611,17 +1617,23 @@ Configure the behavior of the Redis connection pool.
|
||||||
file:
|
file:
|
||||||
- file: /path/to/checked/file
|
- file: /path/to/checked/file
|
||||||
interval: 10s
|
interval: 10s
|
||||||
threshold: 3
|
|
||||||
http:
|
http:
|
||||||
- uri: http://server.to.check/must/return/200
|
- uri: http://server.to.check/must/return/200
|
||||||
|
statuscode: 200
|
||||||
|
timeout: 3s
|
||||||
|
interval: 10s
|
||||||
|
threshold: 3
|
||||||
|
tcp:
|
||||||
|
- addr: redis-server.domain.com:6379
|
||||||
|
timeout: 3s
|
||||||
interval: 10s
|
interval: 10s
|
||||||
threshold: 3
|
threshold: 3
|
||||||
|
|
||||||
The health option is **optional**. It may contain preferences for a periodic
|
The health option is **optional**. It may contain preferences for a periodic
|
||||||
health check on the storage driver's backend storage, and optional periodic
|
health check on the storage driver's backend storage, and optional periodic
|
||||||
checks on local files and/or HTTP URIs. The results of the health checks are
|
checks on local files, HTTP URIs, and/or TCP servers. The results of the health
|
||||||
available at /debug/health on the debug HTTP server if the debug HTTP server is
|
checks are available at /debug/health on the debug HTTP server if the debug
|
||||||
enabled (see http section).
|
HTTP server is enabled (see http section).
|
||||||
|
|
||||||
### storagedriver
|
### storagedriver
|
||||||
|
|
||||||
|
@ -1730,25 +1742,13 @@ The path to check for the existence of a file.
|
||||||
The default value is 10 seconds if this field is omitted.
|
The default value is 10 seconds if this field is omitted.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<code>threshold</code>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
no
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
An integer specifying the number of times the check must fail before the
|
|
||||||
check triggers an unhealthy state. If this filed is not specified, a
|
|
||||||
single failure will trigger an unhealthy state.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
### http
|
### http
|
||||||
|
|
||||||
http is a list of HTTP URIs to be periodically checked with HEAD requests. If
|
http is a list of HTTP URIs to be periodically checked with HEAD requests. If
|
||||||
a HEAD request returns a status code other than 200, the health check will fail.
|
a HEAD request doesn't complete or returns an unexpected status code, the
|
||||||
|
health check will fail.
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1767,6 +1767,122 @@ a HEAD request returns a status code other than 200, the health check will fail.
|
||||||
The URI to check.
|
The URI to check.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>statuscode</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
no
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Expected status code from the HTTP URI. Defaults to 200.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>timeout</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
no
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
The length of time to wait before timing out the HTTP request. This field
|
||||||
|
takes a positive integer and an optional suffix indicating the unit of
|
||||||
|
time. Possible units are:
|
||||||
|
<ul>
|
||||||
|
<li><code>ns</code> (nanoseconds)</li>
|
||||||
|
<li><code>us</code> (microseconds)</li>
|
||||||
|
<li><code>ms</code> (milliseconds)</li>
|
||||||
|
<li><code>s</code> (seconds)</li>
|
||||||
|
<li><code>m</code> (minutes)</li>
|
||||||
|
<li><code>h</code> (hours)</li>
|
||||||
|
</ul>
|
||||||
|
If you omit the suffix, the system interprets the value as nanoseconds.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>interval</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
no
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
The length of time to wait between repetitions of the check. This field
|
||||||
|
takes a positive integer and an optional suffix indicating the unit of
|
||||||
|
time. Possible units are:
|
||||||
|
<ul>
|
||||||
|
<li><code>ns</code> (nanoseconds)</li>
|
||||||
|
<li><code>us</code> (microseconds)</li>
|
||||||
|
<li><code>ms</code> (milliseconds)</li>
|
||||||
|
<li><code>s</code> (seconds)</li>
|
||||||
|
<li><code>m</code> (minutes)</li>
|
||||||
|
<li><code>h</code> (hours)</li>
|
||||||
|
</ul>
|
||||||
|
If you omit the suffix, the system interprets the value as nanoseconds.
|
||||||
|
The default value is 10 seconds if this field is omitted.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>threshold</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
no
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
An integer specifying the number of times the check must fail before the
|
||||||
|
check triggers an unhealthy state. If this filed is not specified, a
|
||||||
|
single failure will trigger an unhealthy state.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
### tcp
|
||||||
|
|
||||||
|
tcp is a list of TCP addresses to be periodically checked with connection
|
||||||
|
attempts. The addresses must include port numbers. If a connection attempt
|
||||||
|
fails, the health check will fail.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Parameter</th>
|
||||||
|
<th>Required</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>addr</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
yes
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
The TCP address to connect to, including a port number.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<code>timeout</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
no
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
The length of time to wait before timing out the TCP connection. This
|
||||||
|
field takes a positive integer and an optional suffix indicating the unit
|
||||||
|
of time. Possible units are:
|
||||||
|
<ul>
|
||||||
|
<li><code>ns</code> (nanoseconds)</li>
|
||||||
|
<li><code>us</code> (microseconds)</li>
|
||||||
|
<li><code>ms</code> (milliseconds)</li>
|
||||||
|
<li><code>s</code> (seconds)</li>
|
||||||
|
<li><code>m</code> (minutes)</li>
|
||||||
|
<li><code>h</code> (hours)</li>
|
||||||
|
</ul>
|
||||||
|
If you omit the suffix, the system interprets the value as nanoseconds.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<code>interval</code>
|
<code>interval</code>
|
||||||
|
|
|
@ -2,15 +2,17 @@ package checks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/distribution/health"
|
"github.com/docker/distribution/health"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileChecker checks the existence of a file and returns and error
|
// FileChecker checks the existence of a file and returns an error
|
||||||
// if the file exists, taking the application out of rotation
|
// if the file exists.
|
||||||
func FileChecker(f string) health.Checker {
|
func FileChecker(f string) health.Checker {
|
||||||
return health.CheckFunc(func() error {
|
return health.CheckFunc(func() error {
|
||||||
if _, err := os.Stat(f); err == nil {
|
if _, err := os.Stat(f); err == nil {
|
||||||
|
@ -20,18 +22,32 @@ func FileChecker(f string) health.Checker {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPChecker does a HEAD request and verifies if the HTTP status
|
// HTTPChecker does a HEAD request and verifies that the HTTP status code
|
||||||
// code return is a 200, taking the application out of rotation if
|
// returned matches statusCode.
|
||||||
// otherwise
|
func HTTPChecker(r string, statusCode int, timeout time.Duration) health.Checker {
|
||||||
func HTTPChecker(r string) health.Checker {
|
|
||||||
return health.CheckFunc(func() error {
|
return health.CheckFunc(func() error {
|
||||||
response, err := http.Head(r)
|
client := http.Client{
|
||||||
|
Timeout: timeout,
|
||||||
|
}
|
||||||
|
response, err := client.Head(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("error while checking: " + r)
|
return errors.New("error while checking: " + r)
|
||||||
}
|
}
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != statusCode {
|
||||||
return errors.New("downstream service returned unexpected status: " + strconv.Itoa(response.StatusCode))
|
return errors.New("downstream service returned unexpected status: " + strconv.Itoa(response.StatusCode))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCPChecker attempts to open a TCP connection.
|
||||||
|
func TCPChecker(addr string, timeout time.Duration) health.Checker {
|
||||||
|
return health.CheckFunc(func() error {
|
||||||
|
conn, err := net.DialTimeout("tcp", addr, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("connection to " + addr + " failed")
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ func TestFileChecker(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPChecker(t *testing.T) {
|
func TestHTTPChecker(t *testing.T) {
|
||||||
if err := HTTPChecker("https://www.google.cybertron").Check(); err == nil {
|
if err := HTTPChecker("https://www.google.cybertron", 200, 0).Check(); err == nil {
|
||||||
t.Errorf("Google on Cybertron was expected as not exists")
|
t.Errorf("Google on Cybertron was expected as not exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := HTTPChecker("https://www.google.pt").Check(); err != nil {
|
if err := HTTPChecker("https://www.google.pt", 200, 0).Check(); err != nil {
|
||||||
t.Errorf("Google at Portugal was expected as exists, error:%v", err)
|
t.Errorf("Google at Portugal was expected as exists, error:%v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,26 +266,46 @@ func (app *App) RegisterHealthChecks(healthRegistries ...*health.Registry) {
|
||||||
if interval == 0 {
|
if interval == 0 {
|
||||||
interval = defaultCheckInterval
|
interval = defaultCheckInterval
|
||||||
}
|
}
|
||||||
if fileChecker.Threshold != 0 {
|
|
||||||
ctxu.GetLogger(app).Infof("configuring file health check path=%s, interval=%d, threshold=%d", fileChecker.File, interval/time.Second, fileChecker.Threshold)
|
|
||||||
healthRegistry.Register(fileChecker.File, health.PeriodicThresholdChecker(checks.FileChecker(fileChecker.File), interval, fileChecker.Threshold))
|
|
||||||
} else {
|
|
||||||
ctxu.GetLogger(app).Infof("configuring file health check path=%s, interval=%d", fileChecker.File, interval/time.Second)
|
ctxu.GetLogger(app).Infof("configuring file health check path=%s, interval=%d", fileChecker.File, interval/time.Second)
|
||||||
healthRegistry.Register(fileChecker.File, health.PeriodicChecker(checks.FileChecker(fileChecker.File), interval))
|
healthRegistry.Register(fileChecker.File, health.PeriodicChecker(checks.FileChecker(fileChecker.File), interval))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, httpChecker := range app.Config.Health.HTTPCheckers {
|
for _, httpChecker := range app.Config.Health.HTTPCheckers {
|
||||||
interval := httpChecker.Interval
|
interval := httpChecker.Interval
|
||||||
if interval == 0 {
|
if interval == 0 {
|
||||||
interval = defaultCheckInterval
|
interval = defaultCheckInterval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusCode := httpChecker.StatusCode
|
||||||
|
if statusCode == 0 {
|
||||||
|
statusCode = 200
|
||||||
|
}
|
||||||
|
|
||||||
|
checker := checks.HTTPChecker(httpChecker.URI, statusCode, httpChecker.Timeout)
|
||||||
|
|
||||||
if httpChecker.Threshold != 0 {
|
if httpChecker.Threshold != 0 {
|
||||||
ctxu.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d, threshold=%d", httpChecker.URI, interval/time.Second, httpChecker.Threshold)
|
ctxu.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d, threshold=%d", httpChecker.URI, interval/time.Second, httpChecker.Threshold)
|
||||||
healthRegistry.Register(httpChecker.URI, health.PeriodicThresholdChecker(checks.HTTPChecker(httpChecker.URI), interval, httpChecker.Threshold))
|
healthRegistry.Register(httpChecker.URI, health.PeriodicThresholdChecker(checker, interval, httpChecker.Threshold))
|
||||||
} else {
|
} else {
|
||||||
ctxu.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d", httpChecker.URI, interval/time.Second)
|
ctxu.GetLogger(app).Infof("configuring HTTP health check uri=%s, interval=%d", httpChecker.URI, interval/time.Second)
|
||||||
healthRegistry.Register(httpChecker.URI, health.PeriodicChecker(checks.HTTPChecker(httpChecker.URI), interval))
|
healthRegistry.Register(httpChecker.URI, health.PeriodicChecker(checker, interval))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tcpChecker := range app.Config.Health.TCPCheckers {
|
||||||
|
interval := tcpChecker.Interval
|
||||||
|
if interval == 0 {
|
||||||
|
interval = defaultCheckInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
checker := checks.TCPChecker(tcpChecker.Addr, tcpChecker.Timeout)
|
||||||
|
|
||||||
|
if tcpChecker.Threshold != 0 {
|
||||||
|
ctxu.GetLogger(app).Infof("configuring TCP health check addr=%s, interval=%d, threshold=%d", tcpChecker.Addr, interval/time.Second, tcpChecker.Threshold)
|
||||||
|
healthRegistry.Register(tcpChecker.Addr, health.PeriodicThresholdChecker(checker, interval, tcpChecker.Threshold))
|
||||||
|
} else {
|
||||||
|
ctxu.GetLogger(app).Infof("configuring TCP health check addr=%s, interval=%d", tcpChecker.Addr, interval/time.Second)
|
||||||
|
healthRegistry.Register(tcpChecker.Addr, health.PeriodicChecker(checker, interval))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
@ -61,6 +62,68 @@ func TestFileHealthCheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTCPHealthCheck(t *testing.T) {
|
||||||
|
interval := time.Second
|
||||||
|
|
||||||
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("could not create listener: %v", err)
|
||||||
|
}
|
||||||
|
addrStr := ln.Addr().String()
|
||||||
|
|
||||||
|
// Start accepting
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
// listener was closed
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
config := configuration.Configuration{
|
||||||
|
Storage: configuration.Storage{
|
||||||
|
"inmemory": configuration.Parameters{},
|
||||||
|
},
|
||||||
|
Health: configuration.Health{
|
||||||
|
TCPCheckers: []configuration.TCPChecker{
|
||||||
|
{
|
||||||
|
Interval: interval,
|
||||||
|
Addr: addrStr,
|
||||||
|
Timeout: 500 * time.Millisecond,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
app := NewApp(ctx, config)
|
||||||
|
healthRegistry := health.NewRegistry()
|
||||||
|
app.RegisterHealthChecks(healthRegistry)
|
||||||
|
|
||||||
|
// Wait for health check to happen
|
||||||
|
<-time.After(2 * interval)
|
||||||
|
|
||||||
|
if len(healthRegistry.CheckStatus()) != 0 {
|
||||||
|
t.Fatal("expected 0 items in health check results")
|
||||||
|
}
|
||||||
|
|
||||||
|
ln.Close()
|
||||||
|
<-time.After(2 * interval)
|
||||||
|
|
||||||
|
// Health check should now fail
|
||||||
|
status := healthRegistry.CheckStatus()
|
||||||
|
if len(status) != 1 {
|
||||||
|
t.Fatal("expected 1 item in health check results")
|
||||||
|
}
|
||||||
|
if status[addrStr] != "connection to "+addrStr+" failed" {
|
||||||
|
t.Fatal(`did not get "connection failed" result for health check`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHTTPHealthCheck(t *testing.T) {
|
func TestHTTPHealthCheck(t *testing.T) {
|
||||||
interval := time.Second
|
interval := time.Second
|
||||||
threshold := 3
|
threshold := 3
|
||||||
|
|
Loading…
Reference in a new issue