Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retry deploy from URL in case of errors #188

Conversation

IvanBorislavovDimitrov
Copy link
Contributor

No description provided.

Comment on lines 394 to 398
return AsyncUploadJobResult{
ClientActions: []string{"RETRY_UPLOAD"},
}, fmt.Errorf("could not get async file upload job %s: %s, body: %s", jobId, resp.Status, string(bodyBytes))
}
return AsyncUploadJobResult{}, fmt.Errorf("could not get async file upload job %s: %s, body: %s", jobId, resp.Status, string(bodyBytes))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse error message as variable

@@ -153,7 +153,7 @@ func (c RetryableMtaRestClient) GetAsyncUploadJob(jobId string, namespace *strin
}
resp, err := baseclient.CallWithRetry(getAsyncUploadJobCb, c.MaxRetriesCount, c.RetryInterval)
if err != nil {
return AsyncUploadJobResult{}, err
return resp.(AsyncUploadJobResult), err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why resp object must be returned now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we can re-use the retry logic:
if resp.StatusCode == 400 { return AsyncUploadJobResult{ ClientActions: []string{"RETRY_UPLOAD"}, }, fmt.Errorf("%s %s: %s, body: %s", couldNotGetAsyncJobError, jobId, resp.Status, string(bodyBytes)) }
In this code the retry is explicitly set and it will be wiped out if we just return an empty object in the retryable client

Comment on lines 338 to 347
for i := 0; i < 3; i++ {
progressBar := c.tryFetchMtarSize(url, disableProgressBar)
uploadFromUrlStatus = c.doUploadFromUrl(encodedFileUrl, mtaClient, namespace, progressBar)
if shouldRetryUpload(uploadFromUrlStatus) {
ui.Warn("Retrying failed upload from URL operation")
continue
}
return uploadFromUrlStatus
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use some general retry mechanism? This custom retry logic is not configurable via --retries command flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored it a bit, so it could be reused. We cannot reuse the other retries, as one is bound to the rest client and the other retries the MTA operation.
Do you think this retry logic should be bound to the --retries, imo it should be used only for retrying the operation, not the upload.
It will be inconsistent to use --retries here, because in the regular upload, there are 3 retries hardcoded

Comment on lines 436 to 442
func shouldRetryUpload(uploadFromUrlStatus UploadFromUrlStatus) bool {
if uploadFromUrlStatus.ExecutionStatus == Success {
return false
}
for _, clientAction := range uploadFromUrlStatus.ClientActions {
if clientAction == "RETRY_UPLOAD" {
return true
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have similar retry mechanism when upload file to the backend of deploy-service?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there's a single request/response, which will be retried by the rest client retry mechanism

time.Sleep(3 * time.Second)
continue
}
return result, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we return err variable instead nil? This way error won't be consumed in this function and will be propagated in the caller function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, fixed

"github.com/cloudfoundry-incubator/multiapps-cli-plugin/log"
)

func Execute[T any](attempts int, callback func() (T, error), shouldRetry func(result T, err error) bool) (T, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really cool


func logError[T any](result T, err error) {
if err != nil {
log.Tracef("retrying an operation that failed with: %v", err)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intentionally lowercase

@IvanBorislavovDimitrov IvanBorislavovDimitrov merged commit 22b5ad9 into cloudfoundry:master Dec 15, 2023
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants