From 312487b71a365aabbc0bf5474bb0a8795eb8a4cb Mon Sep 17 00:00:00 2001 From: Tiago Carreira Date: Thu, 1 Jun 2023 21:05:59 -0300 Subject: [PATCH] add a retry to all write operations (#7) * add a retry to all write operations * refactor to retryRequestOnEventLock() --- hcaas/provider.go | 30 ++++++++++++++++++++++++++++++ hcaas/resource_hcaas_group.go | 23 +++++------------------ hcaas/resource_hcaas_url.go | 22 ++++------------------ hcaas/resource_hcaas_watcher.go | 21 ++++----------------- 4 files changed, 43 insertions(+), 53 deletions(-) diff --git a/hcaas/provider.go b/hcaas/provider.go index 27ef271..2ec0d93 100644 --- a/hcaas/provider.go +++ b/hcaas/provider.go @@ -3,10 +3,14 @@ package hcaas import ( "context" "fmt" + "io/ioutil" + "net/http" "net/url" "strings" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" tsuruCmd "github.com/tsuru/tsuru/cmd" ) @@ -73,3 +77,29 @@ func (h *hcaasProvider) serviceURL(serviceName, instance, path string) string { q.Set("callback", fmt.Sprintf("/resources/%s/%s", instance, strings.TrimLeft(path, "/"))) return fmt.Sprintf("%s/services/%s/proxy/%s?%s", h.Host, serviceName, instance, q.Encode()) } + +// retryRequestOnEventLock will retry the same request if the response is a 5xx containing a "event locked" in the response +func retryRequestOnEventLock(ctx context.Context, d *schema.ResourceData, req *http.Request) error { + return retry.RetryContext(ctx, d.Timeout(schema.TimeoutCreate)-time.Minute, func() *retry.RetryError { + resp, err := http.DefaultClient.Do(req) + + if err != nil { + if strings.Contains(err.Error(), "event locked") { + return retry.RetryableError(err) + } + return retry.NonRetryableError(err) + } + + defer resp.Body.Close() + body, _ := ioutil.ReadAll(resp.Body) + + if resp.StatusCode >= http.StatusInternalServerError && strings.Contains(string(body), "event locked") { + return retry.RetryableError(err) + } + + if resp.StatusCode >= http.StatusBadRequest { + return retry.NonRetryableError(fmt.Errorf("bad status code: %d, body: %q", resp.StatusCode, string(body))) + } + return nil + }) +} diff --git a/hcaas/resource_hcaas_group.go b/hcaas/resource_hcaas_group.go index d57533d..f724458 100644 --- a/hcaas/resource_hcaas_group.go +++ b/hcaas/resource_hcaas_group.go @@ -66,21 +66,14 @@ func resourceHcaasGroupCreate(ctx context.Context, d *schema.ResourceData, meta req.Header.Set("Authorization", provider.Token) - resp, err := http.DefaultClient.Do(req) + err = retryRequestOnEventLock(ctx, d, req) + if err != nil { return diag.FromErr(err) } - - defer resp.Body.Close() - - if resp.StatusCode >= http.StatusBadRequest { - body, _ := ioutil.ReadAll(resp.Body) - return diag.Errorf("Bad status code: %d, body: %q", resp.StatusCode, string(body)) - } - d.SetId(r.Group) - return nil + } func resourceHcaasGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -145,17 +138,11 @@ func resourceHcaasGroupDelete(ctx context.Context, d *schema.ResourceData, meta req.Header.Set("Authorization", provider.Token) - resp, err := http.DefaultClient.Do(req) + err = retryRequestOnEventLock(ctx, d, req) + if err != nil { return diag.FromErr(err) } - - defer resp.Body.Close() - - if resp.StatusCode >= http.StatusBadRequest { - body, _ := ioutil.ReadAll(resp.Body) - return diag.Errorf("Bad status code: %d, body: %q", resp.StatusCode, string(body)) - } return nil } diff --git a/hcaas/resource_hcaas_url.go b/hcaas/resource_hcaas_url.go index 590e34e..fad2305 100644 --- a/hcaas/resource_hcaas_url.go +++ b/hcaas/resource_hcaas_url.go @@ -80,20 +80,12 @@ func resourceHcaasURLCreate(ctx context.Context, d *schema.ResourceData, meta in req.Header.Set("Authorization", provider.Token) - resp, err := http.DefaultClient.Do(req) + err = retryRequestOnEventLock(ctx, d, req) + if err != nil { return diag.FromErr(err) } - - defer resp.Body.Close() - - if resp.StatusCode >= http.StatusBadRequest { - body, _ := ioutil.ReadAll(resp.Body) - return diag.Errorf("Bad status code: %d, body: %q", resp.StatusCode, string(body)) - } - d.SetId(r.URL) - return nil } @@ -162,17 +154,11 @@ func resourceHcaasURLDelete(ctx context.Context, d *schema.ResourceData, meta in req.Header.Set("Authorization", provider.Token) - resp, err := http.DefaultClient.Do(req) + err = retryRequestOnEventLock(ctx, d, req) + if err != nil { return diag.FromErr(err) } - - defer resp.Body.Close() - - if resp.StatusCode >= http.StatusBadRequest { - body, _ := ioutil.ReadAll(resp.Body) - return diag.Errorf("Bad status code: %d, body: %q", resp.StatusCode, string(body)) - } return nil } diff --git a/hcaas/resource_hcaas_watcher.go b/hcaas/resource_hcaas_watcher.go index 2923cc4..1949410 100644 --- a/hcaas/resource_hcaas_watcher.go +++ b/hcaas/resource_hcaas_watcher.go @@ -74,20 +74,12 @@ func resourceHcaasWatcherCreate(ctx context.Context, d *schema.ResourceData, met req.Header.Set("Authorization", provider.Token) - resp, err := http.DefaultClient.Do(req) + err = retryRequestOnEventLock(ctx, d, req) + if err != nil { return diag.FromErr(err) } - - defer resp.Body.Close() - - if resp.StatusCode >= http.StatusBadRequest { - body, _ := ioutil.ReadAll(resp.Body) - return diag.Errorf("Bad status code: %d, body: %q", resp.StatusCode, string(body)) - } - d.SetId(r.Watcher) - return nil } @@ -144,17 +136,12 @@ func resourceHcaasWatcherDelete(ctx context.Context, d *schema.ResourceData, met req.Header.Set("Authorization", provider.Token) - resp, err := http.DefaultClient.Do(req) + err = retryRequestOnEventLock(ctx, d, req) + if err != nil { return diag.FromErr(err) } - defer resp.Body.Close() - - if resp.StatusCode >= http.StatusBadRequest { - body, _ := ioutil.ReadAll(resp.Body) - return diag.Errorf("Bad status code: %d, body: %q", resp.StatusCode, string(body)) - } return nil }