Skip to content
This repository has been archived by the owner on Dec 23, 2024. It is now read-only.

Commit

Permalink
Add context to all Status funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcnunes committed Dec 7, 2023
1 parent d28778f commit 9c15436
Show file tree
Hide file tree
Showing 20 changed files with 108 additions and 73 deletions.
15 changes: 10 additions & 5 deletions checkers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ types of dependencies.

If a pre-built checker is not available, you can create your own checkers by
implementing the `ICheckable` interface (which consists of a single method -
`Status() (interface{}, error)`).
`Status(context.Context) (interface{}, error)`).

If you do create a custom-checker - consider opening a PR and adding it to the
list of built-in checkers.
Expand Down Expand Up @@ -44,17 +44,19 @@ The SQL DB checker has implementations for the following interfaces:
- `SQLExecer`, which encloses `ExecContext` in [`sql.DB`](https://golang.org/pkg/database/sql/#DB.ExecContext), [`sql.Conn`](https://golang.org/pkg/database/sql/#Conn.ExecContext), [`sql.Stmt`](https://golang.org/pkg/database/sql/#Stmt.ExecContext), and [`sql.Tx`](https://golang.org/pkg/database/sql/#Tx.ExecContext)

#### SQLConfig
The `SQLConfig` struct is required when using the SQL DB health check. It **must** contain an inplementation of one of either `SQLPinger`, `SQLQueryer`, or `SQLExecer`.

The `SQLConfig` struct is required when using the SQL DB health check. It **must** contain an inplementation of one of either `SQLPinger`, `SQLQueryer`, or `SQLExecer`.

If `SQLQueryer` or `SQLExecer` are implemented, then `Query` must be valid (len > 0).

Additionally, if `SQLQueryer` or `SQLExecer` are implemented, you have the option to also set either the `QueryerResultHandler` or `ExecerResultHandler` functions. These functions allow you to evaluate the result of a query or exec operation. If you choose not to implement these yourself, the default handlers are used.
Additionally, if `SQLQueryer` or `SQLExecer` are implemented, you have the option to also set either the `QueryerResultHandler` or `ExecerResultHandler` functions. These functions allow you to evaluate the result of a query or exec operation. If you choose not to implement these yourself, the default handlers are used.

The default `ExecerResultHandler` is successful if the passed exec operation affected one and only one row.

The default `QueryerResultHandler` is successful if the passed query operation returned one and only one row.

#### SQLPinger

Use the `SQLPinger` interface if your health check is only concerned with your application's database connectivity. All you need to do is set the `Pinger` value in your `SQLConfig`.

```golang
Expand All @@ -80,11 +82,13 @@ Use the `SQLPinger` interface if your health check is only concerned with your a
```

#### SQLQueryer
Use the `SQLQueryer` interface if your health check requires you to read rows from your database. You can optionally supply a query result handler function. If you don't supply one, the default function will be used. The function signature for the handler is:

Use the `SQLQueryer` interface if your health check requires you to read rows from your database. You can optionally supply a query result handler function. If you don't supply one, the default function will be used. The function signature for the handler is:

```golang
type SQLQueryerResultHandler func(rows *sql.Rows) (bool, error)
```

The default query handler returns true if there was exactly one row in the resultset:

```golang
Expand Down Expand Up @@ -146,7 +150,8 @@ Sample `SQLQueryer` implementation:
```

#### SQLExecer
Use the `SQLExecer` interface if your health check requires you to update or insert to your database. You can optionally supply an exec result handler function. If you don't supply one, the default function will be used. The function signature for the handler is:

Use the `SQLExecer` interface if your health check requires you to update or insert to your database. You can optionally supply an exec result handler function. If you don't supply one, the default function will be used. The function signature for the handler is:

```golang
type SQLExecerResultHandler func(result sql.Result) (bool, error)
Expand Down
10 changes: 7 additions & 3 deletions checkers/disk/disk_usage.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package diskchk

import (
"context"
"fmt"

"github.com/shirou/gopsutil/disk"
Expand All @@ -10,9 +11,12 @@ import (
//
// "Path" is _required_; path to check directory/drive (ex. /home/user)
// "WarningThreshold" is _required_; set percent (more than 0 and less 100) of free space at specified path,
// which triggers warning.
//
// which triggers warning.
//
// "CriticalThreshold" is _required_; set percent (more than 0 and less 100) of free space at specified path,
// which triggers critical.
//
// which triggers critical.
type DiskUsageConfig struct {
Path string
WarningThreshold float64
Expand Down Expand Up @@ -40,7 +44,7 @@ func NewDiskUsage(cfg *DiskUsageConfig) (*DiskUsage, error) {

// Status is used for performing a diskusage check against a dependency; it satisfies
// the "ICheckable" interface.
func (d *DiskUsage) Status() (interface{}, error) {
func (d *DiskUsage) Status(ctx context.Context) (interface{}, error) {
stats, err := disk.Usage(d.Config.Path)

if err != nil {
Expand Down
9 changes: 5 additions & 4 deletions checkers/disk/disk_usage_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package diskchk

import (
"context"
"os"
"testing"

Expand Down Expand Up @@ -98,7 +99,7 @@ func TestDiskUsageStatus(t *testing.T) {
t.Fatal(err)
}

_, err = du.Status()
_, err = du.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Error getting disk usage"))
})
Expand All @@ -115,7 +116,7 @@ func TestDiskUsageStatus(t *testing.T) {
t.Fatal(err)
}

_, err = du.Status()
_, err = du.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Critical: disk usage too high"))
})
Expand All @@ -131,7 +132,7 @@ func TestDiskUsageStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = du.Status()
_, err = du.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Warning: disk usage too high"))
})
Expand All @@ -147,7 +148,7 @@ func TestDiskUsageStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = du.Status()
_, err = du.Status(context.TODO())
Expect(err).To(BeNil())
})
}
3 changes: 2 additions & 1 deletion checkers/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package checkers

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -63,7 +64,7 @@ func NewHTTP(cfg *HTTPConfig) (*HTTP, error) {

// Status is used for performing an HTTP check against a dependency; it satisfies
// the "ICheckable" interface.
func (h *HTTP) Status() (interface{}, error) {
func (h *HTTP) Status(ctx context.Context) (interface{}, error) {
resp, err := h.do()
if err != nil {
return nil, err
Expand Down
14 changes: 8 additions & 6 deletions checkers/http_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package checkers

import (
"context"
"math"
"net/http"
"net/http/httptest"
Expand All @@ -9,6 +10,7 @@ import (
"time"

"fmt"

. "github.com/onsi/gomega"
)

Expand Down Expand Up @@ -164,7 +166,7 @@ func TestHTTPStatus(t *testing.T) {
checker, err := NewHTTP(cfg)
Expect(err).ToNot(HaveOccurred())

data, err := checker.Status()
data, err := checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())
Expect(data).To(BeNil())
})
Expand All @@ -179,7 +181,7 @@ func TestHTTPStatus(t *testing.T) {
checker, err := NewHTTP(cfg)
Expect(err).ToNot(HaveOccurred())

data, err := checker.Status()
data, err := checker.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("unsupported protocol"))
Expect(data).To(BeNil())
Expand All @@ -201,7 +203,7 @@ func TestHTTPStatus(t *testing.T) {
checker, err := NewHTTP(cfg)
Expect(err).ToNot(HaveOccurred())

data, err := checker.Status()
data, err := checker.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("does not match expected status code"))
Expect(data).To(BeNil())
Expand All @@ -225,7 +227,7 @@ func TestHTTPStatus(t *testing.T) {
checker, err := NewHTTP(cfg)
Expect(err).ToNot(HaveOccurred())

data, err := checker.Status()
data, err := checker.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("does not contain expected content"))
Expect(data).To(BeNil())
Expand All @@ -249,7 +251,7 @@ func TestHTTPStatus(t *testing.T) {
checker, err := NewHTTP(cfg)
Expect(err).ToNot(HaveOccurred())

data, err := checker.Status()
data, err := checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())
Expect(data).To(BeNil())
})
Expand Down Expand Up @@ -277,7 +279,7 @@ func TestHTTPStatus(t *testing.T) {
checker, err := NewHTTP(cfg)
Expect(err).ToNot(HaveOccurred())

data, err := checker.Status()
data, err := checker.Status(context.TODO())

Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Unable to read response body to perform content expectancy check"))
Expand Down
3 changes: 2 additions & 1 deletion checkers/memcache/memcached.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package memcachechk

import (
"bytes"
"context"
"fmt"
"net"
"net/url"
Expand Down Expand Up @@ -83,7 +84,7 @@ func NewMemcached(cfg *MemcachedConfig) (*Memcached, error) {
}, nil
}

func (mc *Memcached) Status() (interface{}, error) {
func (mc *Memcached) Status(ctx context.Context) (interface{}, error) {

if mc.Config.Ping {
if _, err := net.Dial("tcp", mc.Config.Url); err != nil {
Expand Down
23 changes: 12 additions & 11 deletions checkers/memcache/memcached_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package memcachechk

import (
"context"
"fmt"
"math/rand"
"strconv"
Expand Down Expand Up @@ -140,10 +141,10 @@ func TestMemcachedStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).To(HaveOccurred())

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err.Error()).To(ContainSubstring("Ping failed"))
})

Expand All @@ -162,7 +163,7 @@ func TestMemcachedStatus(t *testing.T) {
// Mark server is stoppped
server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Unable to complete set"))
})
Expand All @@ -180,7 +181,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())

val, err := checker.wrapper.GetClient().Get(cfg.Set.Key)
Expand All @@ -200,7 +201,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())

val, err := checker.wrapper.GetClient().Get(cfg.Set.Key)
Expand All @@ -221,7 +222,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())

val, err := checker.wrapper.GetClient().Get(cfg.Set.Key)
Expand All @@ -243,7 +244,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).To(HaveOccurred())

Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("Unable to complete get: '%v' not found", cfg.Get.Key)))
Expand All @@ -262,7 +263,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())
})

Expand All @@ -281,7 +282,7 @@ func TestMemcachedStatus(t *testing.T) {
// Close the server so the GET fails
server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Unable to complete get"))
})
Expand All @@ -304,7 +305,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("does not match expected value"))
})
Expand All @@ -325,7 +326,7 @@ func TestMemcachedStatus(t *testing.T) {
}
defer server.Close()

_, err = checker.Status()
_, err = checker.Status(context.TODO())
Expect(err).ToNot(HaveOccurred())
})
})
Expand Down
3 changes: 2 additions & 1 deletion checkers/reachable.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package checkers

import (
"context"
"net"
"net/url"
"time"
Expand Down Expand Up @@ -87,7 +88,7 @@ func NewReachableChecker(cfg *ReachableConfig) (*ReachableChecker, error) {
}

// Status checks if the endpoint is reachable
func (r *ReachableChecker) Status() (interface{}, error) {
func (r *ReachableChecker) Status(ctx context.Context) (interface{}, error) {
// We must provide a port so when a port is not set in the URL provided use
// the default port (80)
port := r.url.Port()
Expand Down
Loading

0 comments on commit 9c15436

Please sign in to comment.