diff options
author | Jaime Martinez <jmartinez@gitlab.com> | 2020-07-27 05:30:13 +0300 |
---|---|---|
committer | Jaime Martinez <jmartinez@gitlab.com> | 2020-08-07 08:12:40 +0300 |
commit | 0ee194529b9c7b3d8a2d8859a24016e7a4d21a1d (patch) | |
tree | 1844856540d605ae098e5f609a78955a9e9dfe7f /internal/source/gitlab | |
parent | a3b311f1522a756997a88aa3dabdf1c46acb0cfa (diff) |
Use exponential backoff for polling
Introudce github.com/cenkalti/backoff/v4 library to use exponential
backoff when polling the Status API.
Diffstat (limited to 'internal/source/gitlab')
-rw-r--r-- | internal/source/gitlab/gitlab.go | 4 | ||||
-rw-r--r-- | internal/source/gitlab/gitlab_poll.go | 66 | ||||
-rw-r--r-- | internal/source/gitlab/gitlab_poll_test.go | 15 |
3 files changed, 54 insertions, 31 deletions
diff --git a/internal/source/gitlab/gitlab.go b/internal/source/gitlab/gitlab.go index 2635d864..67c4eb6b 100644 --- a/internal/source/gitlab/gitlab.go +++ b/internal/source/gitlab/gitlab.go @@ -8,6 +8,8 @@ import ( "strings" "sync" + "github.com/cenkalti/backoff/v4" + "gitlab.com/gitlab-org/gitlab-pages/internal/domain" "gitlab.com/gitlab-org/gitlab-pages/internal/request" "gitlab.com/gitlab-org/gitlab-pages/internal/serving" @@ -36,7 +38,7 @@ func New(config client.Config) (*Gitlab, error) { mu: &sync.RWMutex{}, } - go g.poll(defaultPollingMaxRetries, defaultPollingInterval) + go g.poll(backoff.DefaultInitialInterval, maxPollingTime) // using nil for cache config will use the default values specified in internal/source/gitlab/cache/cache.go#12 return g, nil diff --git a/internal/source/gitlab/gitlab_poll.go b/internal/source/gitlab/gitlab_poll.go index 9fce7250..4e79bbf1 100644 --- a/internal/source/gitlab/gitlab_poll.go +++ b/internal/source/gitlab/gitlab_poll.go @@ -3,37 +3,57 @@ package gitlab import ( "time" + "github.com/cenkalti/backoff/v4" log "github.com/sirupsen/logrus" ) const ( - // defaultPollingMaxRetries to be used by poll - defaultPollingMaxRetries = 30 - // defaultPollingInterval to be used by poll - defaultPollingInterval = time.Minute + // maxPollingTime is the maximum duration to try to call the Status API + maxPollingTime = 60 * time.Minute ) -// poll tries to call the /internal/pages/status API endpoint once plus -// `retries` every `interval`. -// It updates the `isReady` value when successful. +// Poll tries to call the /internal/pages/status API endpoint once plus +// for `maxElapsedTime` // TODO: Remove in https://gitlab.com/gitlab-org/gitlab/-/issues/218357 -func (g *Gitlab) poll(retries int, interval time.Duration) { - var err error - for i := 0; i <= retries; i++ { +func (g *Gitlab) poll(interval, maxElapsedTime time.Duration) { + backOff := backoff.NewExponentialBackOff() + backOff.InitialInterval = interval + backOff.MaxElapsedTime = maxElapsedTime + + op := func() error { log.Info("Checking GitLab internal API availability") - err = g.client.Status() - if err == nil { - log.Info("GitLab internal pages status API connected successfully") - g.mu.Lock() - g.isReady = true - g.mu.Unlock() - - // return as soon as we connect to the API - return - } - - time.Sleep(interval) + + return g.client.Status() + } + + err := backoff.Retry(op, backOff) + if err != nil { + // Handle error. + log.WithError(err).Errorf("Failed to connect to the internal GitLab API after %.2fs", interval.Seconds()) + return } - log.WithError(err).Errorf("Failed to connect to the internal GitLab API after %d tries every %.2fs", retries+1, interval.Seconds()) + g.mu.Lock() + g.isReady = true + g.mu.Unlock() + log.Info("GitLab internal pages status API connected successfully") + // + // var err error + // for i := 0; i <= retries; i++ { + // log.Info("polling GitLab internal pages status API") + // err = g.checker.Status() + // if err == nil { + // log.Info("GitLab internal pages status API connected successfully") + // g.mu.Lock() + // g.isReady = true + // g.mu.Unlock() + // + // // return as soon as we connect to the API + // return + // } + // + // time.Sleep(interval) + // } + // + // log.WithError(err).Errorf("polling failed after %d tries every %.2fs", retries+1, interval.Seconds()) } diff --git a/internal/source/gitlab/gitlab_poll_test.go b/internal/source/gitlab/gitlab_poll_test.go index 01f13846..9a559015 100644 --- a/internal/source/gitlab/gitlab_poll_test.go +++ b/internal/source/gitlab/gitlab_poll_test.go @@ -17,31 +17,31 @@ func TestClient_Poll(t *testing.T) { tests := []struct { name string retries int - interval time.Duration + maxTime time.Duration expectedFail bool }{ { name: "success_with_no_retry", retries: 0, - interval: 5 * time.Millisecond, + maxTime: 10 * time.Millisecond, expectedFail: false, }, { name: "success_after_N_retries", retries: 3, - interval: 10 * time.Millisecond, + maxTime: 30 * time.Millisecond, expectedFail: false, }, { name: "fail_with_no_retries", retries: 0, - interval: 5 * time.Millisecond, + maxTime: 10 * time.Millisecond, expectedFail: true, }, { name: "fail_after_N_retries", retries: 3, - interval: 5 * time.Millisecond, + maxTime: 30 * time.Millisecond, expectedFail: true, }, } @@ -64,10 +64,11 @@ func TestClient_Poll(t *testing.T) { glClient := Gitlab{client: client, mu: &sync.RWMutex{}} - glClient.poll(tt.retries, tt.interval) + glClient.poll(3*time.Millisecond, tt.maxTime) if tt.expectedFail { require.False(t, glClient.isReady) - s := fmt.Sprintf("Failed to connect to the internal GitLab API after %d tries every %.2fs", tt.retries+1, tt.interval.Seconds()) + + s := fmt.Sprintf("\"Failed to connect to the internal GitLab API after %.2fs", tt.maxTime.Seconds()) require.Equal(t, s, hook.LastEntry().Message) return } |