lnd/healthcheck: add healthcheck onSuccess/onFailure callbacks
Allow package users to provide custom callback which will execute whenever a healthcheck fails. Allow package users to provide custom callback which will execute whenever a healthcheck succeeds.
This commit is contained in:
1 file changed
+67
-10
+67
-10
@@ -15,6 +15,8 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/ticker"
|
"github.com/lightningnetwork/lnd/ticker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var noOpCallback = func() {}
|
||||||
|
|
||||||
// Config contains configuration settings for our monitor.
|
// Config contains configuration settings for our monitor.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Checks is a set of health checks that assert that lnd has access to
|
// Checks is a set of health checks that assert that lnd has access to
|
||||||
@@ -150,13 +152,42 @@ type Observation struct {
|
|||||||
// Backoff is the amount of time we back off between retries for failed
|
// Backoff is the amount of time we back off between retries for failed
|
||||||
// checks.
|
// checks.
|
||||||
Backoff time.Duration
|
Backoff time.Duration
|
||||||
|
|
||||||
|
// OnSuccess is a callback which will be executed when the healthcheck
|
||||||
|
// succeeds. This is optional.
|
||||||
|
OnSuccess func()
|
||||||
|
|
||||||
|
// OnFailure is a callback which will be executed when the healthcheck
|
||||||
|
// fails. This is optional.
|
||||||
|
OnFailure func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObservationOption describes the signature of a functional option that can be
|
||||||
|
// used to modify the behaviour of an Observation.
|
||||||
|
type ObservationOption func(*Observation)
|
||||||
|
|
||||||
|
// WithSuccessCallback configures an observation with a callback to be fired
|
||||||
|
// whenever the health check succeeds.
|
||||||
|
func WithSuccessCallback(callback func()) ObservationOption {
|
||||||
|
return func(o *Observation) {
|
||||||
|
o.OnSuccess = callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFailureCallback configures an observation with a callback to be fired
|
||||||
|
// whenever the health check reaches its failure threshold.
|
||||||
|
func WithFailureCallback(callback func()) ObservationOption {
|
||||||
|
return func(o *Observation) {
|
||||||
|
o.OnFailure = callback
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewObservation creates an observation.
|
// NewObservation creates an observation.
|
||||||
func NewObservation(name string, check func() error, interval,
|
func NewObservation(name string, check func() error, interval, timeout,
|
||||||
timeout, backoff time.Duration, attempts int) *Observation {
|
backoff time.Duration, attempts int,
|
||||||
|
opts ...ObservationOption) *Observation {
|
||||||
|
|
||||||
return &Observation{
|
observation := &Observation{
|
||||||
Name: name,
|
Name: name,
|
||||||
Check: CreateCheck(check),
|
Check: CreateCheck(check),
|
||||||
Interval: ticker.New(interval),
|
Interval: ticker.New(interval),
|
||||||
@@ -164,6 +195,22 @@ func NewObservation(name string, check func() error, interval,
|
|||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
Backoff: backoff,
|
Backoff: backoff,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply each option to the observation.
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(observation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that we default to NO-OP callbacks.
|
||||||
|
if observation.OnSuccess == nil {
|
||||||
|
observation.OnSuccess = noOpCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
if observation.OnFailure == nil {
|
||||||
|
observation.OnFailure = noOpCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
return observation
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of an observation.
|
// String returns a string representation of an observation.
|
||||||
@@ -219,6 +266,17 @@ func (o *Observation) retryCheck(quit chan struct{},
|
|||||||
var err error
|
var err error
|
||||||
select {
|
select {
|
||||||
case err = <-o.Check():
|
case err = <-o.Check():
|
||||||
|
// If our error is nil, we have passed our health check,
|
||||||
|
// so we'll invoke our success callback if defined and
|
||||||
|
// then exit.
|
||||||
|
if err == nil {
|
||||||
|
log.Debug("invoking success callback")
|
||||||
|
|
||||||
|
// Invoke the success callback.
|
||||||
|
o.OnSuccess()
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
case <-time.After(o.Timeout):
|
case <-time.After(o.Timeout):
|
||||||
err = fmt.Errorf("health check: %v timed out after: "+
|
err = fmt.Errorf("health check: %v timed out after: "+
|
||||||
@@ -229,15 +287,14 @@ func (o *Observation) retryCheck(quit chan struct{},
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// If our error is nil, we have passed our health check, so we
|
|
||||||
// can exit.
|
|
||||||
if err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have reached our allowed number of attempts, this
|
// If we have reached our allowed number of attempts, this
|
||||||
// check has failed so we request shutdown.
|
// check has failed so we'll fire the on failure callback
|
||||||
|
// and request shutdown.
|
||||||
if count == o.Attempts {
|
if count == o.Attempts {
|
||||||
|
log.Debug("invoking failure callback")
|
||||||
|
|
||||||
|
o.OnFailure()
|
||||||
|
|
||||||
shutdown("Health check: %v failed after %v "+
|
shutdown("Health check: %v failed after %v "+
|
||||||
"calls", o, o.Attempts)
|
"calls", o, o.Attempts)
|
||||||
return true
|
return true
|
||||||
|
|||||||
Reference in new issue
Block a user