From bad16672191cedd2f51d5ceb91a46d738e3ecd04 Mon Sep 17 00:00:00 2001 From: Foteini Giouleka Date: Wed, 24 Apr 2024 12:54:41 +0300 Subject: [PATCH] Extend retry mechanism for specific api errors --- internal/txlib/merge.go | 2 +- internal/txlib/pull.go | 8 ++++---- internal/txlib/push.go | 8 ++++---- internal/txlib/utils.go | 10 +++++----- pkg/jsonapi/connection.go | 6 +++--- pkg/jsonapi/errors.go | 39 +++++++++++++++++++++------------------ 6 files changed, 38 insertions(+), 35 deletions(-) diff --git a/internal/txlib/merge.go b/internal/txlib/merge.go index ce457f6..5b73deb 100644 --- a/internal/txlib/merge.go +++ b/internal/txlib/merge.go @@ -109,7 +109,7 @@ func (task *MergeResourcePollTask) Run(send func(string), abort func()) { )) } - err := handleThrottling( + err := handleRetry( func() error { return txapi.PollResourceMerge( merge, diff --git a/internal/txlib/pull.go b/internal/txlib/pull.go index 48e4717..106fbde 100644 --- a/internal/txlib/pull.go +++ b/internal/txlib/pull.go @@ -409,7 +409,7 @@ func (task *FilePullTask) Run(send func(string), abort func()) { // Creating download job var download *jsonapi.Resource - err = handleThrottling( + err = handleRetry( func() error { var err error download, err = txapi.CreateResourceStringsAsyncDownload( @@ -434,7 +434,7 @@ func (task *FilePullTask) Run(send func(string), abort func()) { // Polling - err = handleThrottling( + err = handleRetry( func() error { return txapi.PollResourceStringsDownload(download, sourceFile) }, @@ -513,7 +513,7 @@ func (task *FilePullTask) Run(send func(string), abort func()) { // Creating download job var download *jsonapi.Resource - err = handleThrottling( + err = handleRetry( func() error { var err error if args.Pseudo { @@ -549,7 +549,7 @@ func (task *FilePullTask) Run(send func(string), abort func()) { // Polling - err = handleThrottling( + err = handleRetry( func() error { return txapi.PollTranslationDownload(download, filePath) }, diff --git a/internal/txlib/push.go b/internal/txlib/push.go index 4799a11..2d6479c 100644 --- a/internal/txlib/push.go +++ b/internal/txlib/push.go @@ -629,7 +629,7 @@ func (task *SourceFilePushTask) Run(send func(string), abort func()) { // Uploading file var sourceUpload *jsonapi.Resource - err = handleThrottling( + err = handleRetry( func() error { var err error sourceUpload, err = txapi.UploadSource( @@ -650,7 +650,7 @@ func (task *SourceFilePushTask) Run(send func(string), abort func()) { // Polling - err = handleThrottling( + err = handleRetry( func() error { return txapi.PollSourceUpload(sourceUpload) }, @@ -722,7 +722,7 @@ func (task *TranslationFileTask) Run(send func(string), abort func()) { // Uploading file var upload *jsonapi.Resource - err := handleThrottling( + err := handleRetry( func() error { var err error upload, err = pushTranslation( @@ -742,7 +742,7 @@ func (task *TranslationFileTask) Run(send func(string), abort func()) { } // Polling - err = handleThrottling( + err = handleRetry( func() error { return txapi.PollTranslationUpload(upload) }, diff --git a/internal/txlib/utils.go b/internal/txlib/utils.go index 6a7576d..f224d88 100644 --- a/internal/txlib/utils.go +++ b/internal/txlib/utils.go @@ -153,11 +153,11 @@ func makeRemoteToLocalLanguageMappings( } /* -Run 'do'. If the error returned by 'do' is a jsonapi.ThrottleError, sleep the number of +Run 'do'. If the error returned by 'do' is a jsonapi.RetryError, sleep the number of seconds indicated by the error and try again. Meanwhile, inform the user of what's going on using 'send'. */ -func handleThrottling(do func() error, initialMsg string, send func(string)) error { +func handleRetry(do func() error, initialMsg string, send func(string)) error { for { if len(initialMsg) > 0 { send(initialMsg) @@ -166,13 +166,13 @@ func handleThrottling(do func() error, initialMsg string, send func(string)) err if err == nil { return nil } else { - var e *jsonapi.ThrottleError + var e *jsonapi.RetryError if errors.As(err, &e) { retryAfter := e.RetryAfter if isatty.IsTerminal(os.Stdout.Fd()) { for retryAfter > 0 { send(fmt.Sprintf( - "Throttled, will retry after %d seconds", + "will retry after %d seconds", retryAfter, )) time.Sleep(time.Second) @@ -180,7 +180,7 @@ func handleThrottling(do func() error, initialMsg string, send func(string)) err } } else { send(fmt.Sprintf( - "Throttled, will retry after %d seconds", + "will retry after %d seconds", retryAfter, )) time.Sleep(time.Duration(retryAfter) * time.Second) diff --git a/pkg/jsonapi/connection.go b/pkg/jsonapi/connection.go index df27c12..45eeca4 100644 --- a/pkg/jsonapi/connection.go +++ b/pkg/jsonapi/connection.go @@ -65,9 +65,9 @@ func (c *Connection) request( } defer response.Body.Close() - throttleErrorResponse := parseThrottleResponse(response) - if throttleErrorResponse != nil { - return nil, throttleErrorResponse + retryErrorResponse := parseRetryResponse(response) + if retryErrorResponse != nil { + return nil, retryErrorResponse } errorResponse := parseErrorResponse(response.StatusCode, body) diff --git a/pkg/jsonapi/errors.go b/pkg/jsonapi/errors.go index 469cf74..3f42577 100644 --- a/pkg/jsonapi/errors.go +++ b/pkg/jsonapi/errors.go @@ -14,19 +14,19 @@ Error type for {json:api} errors. You can inspect the contents of the error response with type assertions. Example: - project := jsonapi.Resource{...} - err := project.Save() // Here the server responds with an error - switch e := err.(type) { - case *jsonapi.Error: - // "Smartly" inspect the contents of the error - for _, errorItem := range e.Errors { - if errorItem.Status == "404" { - fmt.Println("Something was not found") + project := jsonapi.Resource{...} + err := project.Save() // Here the server responds with an error + switch e := err.(type) { + case *jsonapi.Error: + // "Smartly" inspect the contents of the error + for _, errorItem := range e.Errors { + if errorItem.Status == "404" { + fmt.Println("Something was not found") + } } - } - default: - fmt.Printf("%s\n", e) - } + default: + fmt.Printf("%s\n", e) + } */ type Error struct { StatusCode int @@ -77,21 +77,24 @@ func (m *RedirectError) Error() string { "`var e *jsonapi.RedirectError; errors.As(err, &e); e.Location`" } -type ThrottleError struct { +type RetryError struct { RetryAfter int } -func (err ThrottleError) Error() string { +func (err RetryError) Error() string { return fmt.Sprintf("throttled; retry after %d", err.RetryAfter) } -func parseThrottleResponse(response *http.Response) *ThrottleError { - if response.StatusCode != 429 { +func parseRetryResponse(response *http.Response) *RetryError { + if response.StatusCode != 429 && + response.StatusCode != 502 && + response.StatusCode != 503 && + response.StatusCode != 504 { return nil } retryAfter, err := strconv.Atoi(response.Header.Get("Retry-After")) if err != nil { - return &ThrottleError{1} + return &RetryError{1} } - return &ThrottleError{retryAfter} + return &RetryError{retryAfter} }