Skip to content

Commit

Permalink
Merge pull request #217 from transifex/TX-15322_retry
Browse files Browse the repository at this point in the history
Extend retry mechanism for specific api errors
  • Loading branch information
foteinigk committed Apr 24, 2024
2 parents ee2462a + bad1667 commit 673b0e1
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 35 deletions.
2 changes: 1 addition & 1 deletion internal/txlib/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (task *MergeResourcePollTask) Run(send func(string), abort func()) {
))
}

err := handleThrottling(
err := handleRetry(
func() error {
return txapi.PollResourceMerge(
merge,
Expand Down
8 changes: 4 additions & 4 deletions internal/txlib/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
},
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
},
Expand Down
8 changes: 4 additions & 4 deletions internal/txlib/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -650,7 +650,7 @@ func (task *SourceFilePushTask) Run(send func(string), abort func()) {

// Polling

err = handleThrottling(
err = handleRetry(
func() error {
return txapi.PollSourceUpload(sourceUpload)
},
Expand Down Expand Up @@ -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(
Expand All @@ -742,7 +742,7 @@ func (task *TranslationFileTask) Run(send func(string), abort func()) {
}

// Polling
err = handleThrottling(
err = handleRetry(
func() error {
return txapi.PollTranslationUpload(upload)
},
Expand Down
10 changes: 5 additions & 5 deletions internal/txlib/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -166,21 +166,21 @@ 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)
retryAfter -= 1
}
} else {
send(fmt.Sprintf(
"Throttled, will retry after %d seconds",
"will retry after %d seconds",
retryAfter,
))
time.Sleep(time.Duration(retryAfter) * time.Second)
Expand Down
6 changes: 3 additions & 3 deletions pkg/jsonapi/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
39 changes: 21 additions & 18 deletions pkg/jsonapi/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}
}

0 comments on commit 673b0e1

Please sign in to comment.