From 8dc7f27400075fabca9525f42eb20404736fb1cb Mon Sep 17 00:00:00 2001 From: Piotr Icikowski Date: Sun, 3 Mar 2024 23:24:42 +0100 Subject: [PATCH] refactor(probes): rename `ProbeFunction` to `Probe` --- README.md | 26 ++++++++++++++------------ kubeprobes.go | 8 ++++---- kubeprobes_options.go | 4 ++-- probe_function.go => probe.go | 22 +++++++++++----------- probe_manual.go | 2 +- query.go | 2 +- query_test.go | 12 ++++++------ 7 files changed, 39 insertions(+), 37 deletions(-) rename probe_function.go => probe.go (72%) diff --git a/README.md b/README.md index d080cf8..894450c 100644 --- a/README.md +++ b/README.md @@ -21,22 +21,22 @@ Default paths can be overriden with options described below. Accessing any other The `kubeprobes.New` function accepts following options as arguments: -- `kubeprobes.WithLivenessProbes(...)` - adds particular [probe functions](#probe-functions) to the list of liveness probes; +- `kubeprobes.WithLivenessProbes(...)` - adds particular [probes](#probes) to the list of liveness probes; - `kubeprobes.WithLivenessPath("/some/liveness/path")` - sets liveness probe path to given path (default is `/live`); -- `kubeprobes.WithReadinessProbes(...)` - adds particular [probe functions](#probe-functions) to the list of readiness probes; +- `kubeprobes.WithReadinessProbes(...)` - adds particular [probes](#probes) to the list of readiness probes; - `kubeprobes.WithReadinessPath("/some/readiness/path")` - sets readiness probe path to given path (default is `/ready`); - `kubeprobes.WithVerboseOutput()` - enables verbose output by default (returns both failed and passed probes). ## Probes -In order to determine the state of particular element of application, probes need to be implemented either by creating [status determining function](#probe-functions) or by using simple and thread-safe [manual probes](#manual-probes). +In order to determine the state of particular element of application, probes need to be implemented either by creating [probes from functions](#standard-probes) or by using simple and thread-safe [manual probes](#manual-probes). -### Probe functions +### Standard probes -Probe functions (instances of `ProbeFunction` interface) are wrappers for functions that performs user defined logic with given interval of updates in order to determine whether the probe should be marked as healthy or not. Those functions should take no arguments and return error (if no error is returned, the probe is considered to be healthy; if error is returned, the probe is considered to be unhealthy). If given interval is less or equal zero, then function is only checked on probe creation and remains in determined state forever. +Probes (instances of `Probe` interface) are wrappers for functions that performs user defined logic with given interval of updates in order to determine whether the probe should be marked as healthy or not. Those functions should take no arguments and return error (if no error is returned, the probe is considered to be healthy; if error is returned, the probe is considered to be unhealthy). If given interval is less or equal zero, then function is only checked on probe creation and remains in determined state forever. ```go -someProbe := kubeprobes.NewProbeFunction("live", func() error { +someProbe := kubeprobes.NewProbe("live", func() error { // Some logic here if time.Now().Weekday() == time.Wednesday { // Fail only on wednesday! @@ -45,7 +45,7 @@ someProbe := kubeprobes.NewProbeFunction("live", func() error { return nil }, 1 * time.Hour) -someOtherProbe := kubeprobes.NewProbeFunction("ready", func() error { +someOtherProbe := kubeprobes.NewProbe("ready", func() error { // Always healthy return nil }, 0) // This probe is checked once @@ -59,7 +59,7 @@ kp, _ := kubeprobes.New( ### Manual probes -Manual probes (instances of `ManualProbe` interface) are objects that can be marked either as healthy or unhealthy and implement `ProbeFunction` for easy integration. Those objects utilize `sync.RMutex` mechanism to ensure thread-safety. +Manual probes (instances of `ManualProbe` interface) are objects that can be marked either as healthy or unhealthy and implement `Probe` for easy integration. Those objects utilize `sync.RMutex` mechanism to ensure thread-safety. Those probes can be changed by user with provided methods: @@ -78,7 +78,9 @@ kp, _ := kubeprobes.New( kubeprobes.WithReadinessProbes(someOtherProbe), ) -// Can be later marked according +// Can be later marked according to needs +someProbe.Pass() +someOtherProbe.FailWithCause(errors.New("I'm not doing anything!")) ``` ## Direct handler access @@ -105,9 +107,9 @@ appProbe := func() error { return nil } -// Create stateful probes -live := kubeprobes.NewStatefulProbe() -ready := kubeprobes.NewStatefulProbe() +// Create manual probes +live := kubeprobes.NewManualProbe() +ready := kubeprobes.NewManualProbe() // Prepare handler kp, err := kubeprobes.New( diff --git a/kubeprobes.go b/kubeprobes.go index c6c188a..61804ff 100644 --- a/kubeprobes.go +++ b/kubeprobes.go @@ -19,8 +19,8 @@ type Kubeprobes interface { } type kubeprobes struct { - livenessProbes []ProbeFunction - readinessProbes []ProbeFunction + livenessProbes []Probe + readinessProbes []Probe verbose bool @@ -31,8 +31,8 @@ type kubeprobes struct { // New returns a new instance of a Kubernetes probes with given options. func New(options ...Option) (Kubeprobes, error) { kp := &kubeprobes{ - livenessProbes: []ProbeFunction{}, - readinessProbes: []ProbeFunction{}, + livenessProbes: []Probe{}, + readinessProbes: []Probe{}, pathLive: defaultLivenessPath, pathReady: defaultReadinessPath, } diff --git a/kubeprobes_options.go b/kubeprobes_options.go index c2f3456..91d7e82 100644 --- a/kubeprobes_options.go +++ b/kubeprobes_options.go @@ -12,7 +12,7 @@ func (o option) apply(kp *kubeprobes) { } // WithLivenessProbes adds given probe functions to the set of liveness probes. -func WithLivenessProbes(probes ...ProbeFunction) Option { +func WithLivenessProbes(probes ...Probe) Option { return option(func(kp *kubeprobes) { kp.livenessProbes = append(kp.livenessProbes, probes...) }) @@ -26,7 +26,7 @@ func WithLivenessPath(path string) Option { } // WithReadinessProbes adds given probe functions to the set of readiness probes. -func WithReadinessProbes(probes ...ProbeFunction) Option { +func WithReadinessProbes(probes ...Probe) Option { return option(func(kp *kubeprobes) { kp.readinessProbes = append(kp.readinessProbes, probes...) }) diff --git a/probe_function.go b/probe.go similarity index 72% rename from probe_function.go rename to probe.go index 1036e25..3c5a3a1 100644 --- a/probe_function.go +++ b/probe.go @@ -5,15 +5,15 @@ import ( "time" ) -// ProbeFunction is a wrapper for a function that determines whether +// Probe is a wrapper for a function that determines whether // the given metric may be marked as correctly functioning. // It not, the error should be returned. -type ProbeFunction interface { +type Probe interface { name() string status() error } -type probeFunction struct { +type probe struct { probeName string probeFunc func() error refreshInterval time.Duration @@ -22,20 +22,20 @@ type probeFunction struct { err error } -// NewProbeFunction returns new instance of [ProbeFunction]. +// NewProbe returns new instance of [Probe]. // // If update interval is less or equal zero then probe is updated only // on its creation and remains in the same state forever. -func NewProbeFunction( +func NewProbe( name string, fn func() error, updateInterval time.Duration, -) (ProbeFunction, error) { +) (Probe, error) { if name == "" { return nil, errProbeNameEmpty } - pf := &probeFunction{ + pf := &probe{ probeName: name, probeFunc: fn, refreshInterval: updateInterval, @@ -47,25 +47,25 @@ func NewProbeFunction( } // name implements ProbeFunction. -func (pf *probeFunction) name() string { +func (pf *probe) name() string { return pf.probeName } // status implements ProbeFunction. -func (pf *probeFunction) status() error { +func (pf *probe) status() error { pf.mux.RLock() defer pf.mux.RUnlock() return pf.err } -func (pf *probeFunction) update() { +func (pf *probe) update() { err := pf.probeFunc() pf.mux.Lock() pf.err = err pf.mux.Unlock() } -func (pf *probeFunction) autoUpdate() { +func (pf *probe) autoUpdate() { pf.update() if pf.refreshInterval <= 0 { return diff --git a/probe_manual.go b/probe_manual.go index c6e839f..6c05ef0 100644 --- a/probe_manual.go +++ b/probe_manual.go @@ -7,7 +7,7 @@ import ( // ManualProbe represents the simple probe that can be either // marked as "up" (healthy) or "down" (unhealthy). type ManualProbe interface { - ProbeFunction + Probe // Pass marks the probe as healthy. Pass() diff --git a/query.go b/query.go index 5e8939a..c5763ae 100644 --- a/query.go +++ b/query.go @@ -20,7 +20,7 @@ func (sq *statusQuery) wait() { sq.wg.Wait() } -func newStatusQuery(probes []ProbeFunction) *statusQuery { +func newStatusQuery(probes []Probe) *statusQuery { sq := &statusQuery{ ok: true, passed: make([]statusEntry, 0, len(probes)), diff --git a/query_test.go b/query_test.go index 911c16a..7a37f96 100644 --- a/query_test.go +++ b/query_test.go @@ -6,28 +6,28 @@ import ( func TestStatusQueryIsAllGreen(t *testing.T) { var ( - probePassing, _ = NewProbeFunction("pass", func() error { + probePassing, _ = NewProbe("pass", func() error { return nil }, 0) - probeFailing, _ = NewProbeFunction("fail", func() error { + probeFailing, _ = NewProbe("fail", func() error { return errProbeFailed }, 0) ) tests := map[string]struct { - probes []ProbeFunction + probes []Probe expectedStatus bool }{ "all green": { - probes: []ProbeFunction{probePassing}, + probes: []Probe{probePassing}, expectedStatus: true, }, "some failed": { - probes: []ProbeFunction{probePassing, probeFailing}, + probes: []Probe{probePassing, probeFailing}, expectedStatus: false, }, "all failed": { - probes: []ProbeFunction{probeFailing}, + probes: []Probe{probeFailing}, expectedStatus: false, }, }