Skip to content

Commit

Permalink
feat: server state check functions improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
vlastahajek committed Nov 11, 2021
1 parent 459bc63 commit f0811a5
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 23 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
## unreleased
## Unreleased
### Features
- [#285](https://github.com/influxdata/influxdb-client-go/pull/285) Added *Client.Ping()* function which returns status where server is available. This the only validation method available for both OSS and Cloud.

### Bug fixes
- [#285](https://github.com/influxdata/influxdb-client-go/pull/285) Functions *Client.Health()* and *Client.Ready()* correctly reports error when calling them against InfluxDB Cloud, where those endpoints are not available.

### Features
### Breaking change
- [#285](https://github.com/influxdata/influxdb-client-go/pull/285) Functions *Client.Ready()* now returns full uptime info as returned by server.


## 2.5.1[2021-09-17]
### Bug fixes
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,17 @@ httpClient := &http.Client{
client := influxdb2.NewClientWithOptions("http://localhost:8086", token, influxdb2.DefaultOptions().SetHTTPClient(httpClient))
```
### Checking Server State
There are three functions for checking server is up and ready for communication:
| Function| Description | Availability |
|:----------|:----------|:----------|
| [Health()](https://pkg.go.dev/github.com/influxdata/influxdb-client-go/v2#Client.Health) | Detailed info about the server status, along with version string | OSS |
| [Ready()](https://pkg.go.dev/github.com/influxdata/influxdb-client-go/v2#Client.Ready) | Server uptime info | OSS |
| [Ping()](https://pkg.go.dev/github.com/influxdata/influxdb-client-go/v2#Client.Ping) | Whether a server is up | OSS, Cloud |
Only the [Ping()](https://pkg.go.dev/github.com/influxdata/influxdb-client-go/v2#Client.Ping) function is able to return status of an Influx DB Cloud server.
## InfluxDB 1.8 API compatibility
[InfluxDB 1.8.0 introduced forward compatibility APIs](https://docs.influxdata.com/influxdb/latest/tools/api/#influxdb-2-0-api-compatibility-endpoints) for InfluxDB 2.0. This allow you to easily move from InfluxDB 1.x to InfluxDB 2.0 Cloud or open source.
Expand Down
8 changes: 4 additions & 4 deletions api/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,23 @@ func TestGzipWithFlushing(t *testing.T) {
}
func TestFlushInterval(t *testing.T) {
service := test.NewTestService(t, "http://localhost:8888")
writeAPI := NewWriteAPI("my-org", "my-bucket", service, write.DefaultOptions().SetBatchSize(10).SetFlushInterval(10))
writeAPI := NewWriteAPI("my-org", "my-bucket", service, write.DefaultOptions().SetBatchSize(10).SetFlushInterval(30))
points := test.GenPoints(5)
for _, p := range points {
writeAPI.WritePoint(p)
}
require.Len(t, service.Lines(), 0)
<-time.After(time.Millisecond * 15)
<-time.After(time.Millisecond * 50)
require.Len(t, service.Lines(), 5)
writeAPI.Close()

service.Close()
writeAPI = NewWriteAPI("my-org", "my-bucket", service, writeAPI.writeOptions.SetFlushInterval(50))
writeAPI = NewWriteAPI("my-org", "my-bucket", service, writeAPI.writeOptions.SetFlushInterval(500))
for _, p := range points {
writeAPI.WritePoint(p)
}
require.Len(t, service.Lines(), 0)
<-time.After(time.Millisecond * 60)
<-time.After(time.Millisecond * 550)
require.Len(t, service.Lines(), 5)

writeAPI.Close()
Expand Down
29 changes: 23 additions & 6 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ type Client interface {
// and returns details about newly created entities along with the authorization object.
// Retention period of zero will result to infinite retention.
Setup(ctx context.Context, username, password, org, bucket string, retentionPeriodHours int) (*domain.OnboardingResponse, error)
// Ready checks InfluxDB server is running. It doesn't validate authentication params.
Ready(ctx context.Context) (bool, error)
// Ready returns InfluxDB uptime info of server. It doesn't validate authentication params.
Ready(ctx context.Context) (*domain.Ready, error)
// Health returns an InfluxDB server health check result. Read the HealthCheck.Status field to get server status.
// Health doesn't validate authentication params.
Health(ctx context.Context) (*domain.HealthCheck, error)
// Ping validates InfluxDB server is running. It doesn't validate authentication params.
Ping(ctx context.Context) (bool, error)
// Close ensures all ongoing asynchronous write clients finish.
// Also closes all idle connections, in case of HTTP client was created internally.
Close()
Expand Down Expand Up @@ -136,16 +138,20 @@ func (c *clientImpl) HTTPService() http.Service {
return c.httpService
}

func (c *clientImpl) Ready(ctx context.Context) (bool, error) {
func (c *clientImpl) Ready(ctx context.Context) (*domain.Ready, error) {
params := &domain.GetReadyParams{}
response, err := c.apiClient.GetReadyWithResponse(ctx, params)
if err != nil {
return false, err
return nil, err
}
if response.JSONDefault != nil {
return false, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode())
return nil, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode())
}
return true, nil
if response.JSON200 == nil { //response with status 2xx, but not JSON
return nil, errors.New("cannot read Ready response")

}
return response.JSON200, nil
}

func (c *clientImpl) Setup(ctx context.Context, username, password, org, bucket string, retentionPeriodHours int) (*domain.OnboardingResponse, error) {
Expand Down Expand Up @@ -189,10 +195,21 @@ func (c *clientImpl) Health(ctx context.Context) (*domain.HealthCheck, error) {
//unhealthy server
return response.JSON503, nil
}
if response.JSON200 == nil { //response with status 2xx, but not JSON
return nil, errors.New("cannot read Health response")
}

return response.JSON200, nil
}

func (c *clientImpl) Ping(ctx context.Context) (bool, error) {
resp, err := c.apiClient.GetPingWithResponse(ctx)
if err != nil {
return false, err
}
return resp.StatusCode() == 204, nil
}

func createKey(org, bucket string) string {
return org + "\t" + bucket
}
Expand Down
48 changes: 41 additions & 7 deletions client_e2e_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build e2e
// +build e2e

// Copyright 2020-2021 InfluxData, Inc. All rights reserved.
Expand Down Expand Up @@ -63,13 +64,14 @@ func TestSetup(t *testing.T) {
func TestReady(t *testing.T) {
client := influxdb2.NewClient(serverURL, "")

ok, err := client.Ready(context.Background())
if err != nil {
t.Error(err)
}
if !ok {
t.Fail()
}
ready, err := client.Ready(context.Background())
require.NoError(t, err)
require.NotNil(t, ready)
require.NotNil(t, ready.Started)
assert.True(t, ready.Started.Before(time.Now()))
dur, err := time.ParseDuration(*ready.Up)
require.NoError(t, err)
assert.True(t, dur.Seconds() > 0)
}

func TestHealth(t *testing.T) {
Expand All @@ -83,6 +85,14 @@ func TestHealth(t *testing.T) {
assert.Equal(t, domain.HealthCheckStatusPass, health.Status)
}

func TestPing(t *testing.T) {
client := influxdb2.NewClient(serverURL, "")

ok, err := client.Ping(context.Background())
require.NoError(t, err)
assert.True(t, ok)
}

func TestWrite(t *testing.T) {
client := influxdb2.NewClientWithOptions(serverURL, authToken, influxdb2.DefaultOptions().SetLogLevel(3))
writeAPI := client.WriteAPI("my-org", "my-bucket")
Expand Down Expand Up @@ -161,6 +171,14 @@ func TestQuery(t *testing.T) {

}

func TestPingV1(t *testing.T) {
client := influxdb2.NewClient(serverV1URL, "")

ok, err := client.Ping(context.Background())
require.NoError(t, err)
assert.True(t, ok)
}

func TestHealthV1Compatibility(t *testing.T) {
client := influxdb2.NewClient(serverV1URL, "")

Expand Down Expand Up @@ -328,3 +346,19 @@ func TestLogsConcurrent(t *testing.T) {
}
wg.Wait()
}

func TestReadyCloud(t *testing.T) {
client := influxdb2.NewClient("https://eu-central-1-1.aws.cloud2.influxdata.com", "HVulIwn4feMInt5DMACi6b03iSmrHW2-DCDbcI2n_TP3wAS726duAHRK033WqO3bNn9uWziIINDdQ3HXFOxikg==")

r, err := client.Ready(context.Background())
assert.Error(t, err)
assert.Nil(t, r)
}

func TestHealthCloud(t *testing.T) {
client := influxdb2.NewClient("https://eu-central-1-1.aws.cloud2.influxdata.com", "HVulIwn4feMInt5DMACi6b03iSmrHW2-DCDbcI2n_TP3wAS726duAHRK033WqO3bNn9uWziIINDdQ3HXFOxikg==")

h, err := client.Health(context.Background())
assert.Error(t, err)
assert.Nil(t, h)
}
34 changes: 30 additions & 4 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ func TestUserAgent(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
<-time.After(100 * time.Millisecond)
if r.Header.Get("User-Agent") == http2.UserAgent {
w.WriteHeader(http.StatusOK)
w.WriteHeader(http.StatusNoContent)
} else {
w.WriteHeader(http.StatusNotFound)
}
}))

defer server.Close()
c := NewClient(server.URL, "x")
ready, err := c.Ready(context.Background())
assert.True(t, ready)
assert.Nil(t, err)
up, err := c.Ping(context.Background())
require.NoError(t, err)
assert.True(t, up)

err = c.WriteAPIBlocking("o", "b").WriteRecord(context.Background(), "a,a=a a=1i")
assert.NoError(t, err)
Expand Down Expand Up @@ -167,3 +167,29 @@ func TestServerErrorEmptyBody(t *testing.T) {
require.Error(t, err)
assert.Equal(t, "Unexpected status code 404", err.Error())
}

func TestReadyFail(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Write([]byte(`<html></html>`))
}))

defer server.Close()
c := NewClient(server.URL, "x")
r, err := c.Ready(context.Background())
assert.Error(t, err)
assert.Nil(t, r)
}

func TestHealthFail(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Write([]byte(`<html></html>`))
}))

defer server.Close()
c := NewClient(server.URL, "x")
h, err := c.Health(context.Background())
assert.Error(t, err)
assert.Nil(t, h)
}

0 comments on commit f0811a5

Please sign in to comment.