From f9bf9bc1aa4fd24ead1692193079dca8908dfb32 Mon Sep 17 00:00:00 2001 From: Abhishek Pandey Date: Fri, 29 Dec 2023 17:18:11 -0800 Subject: [PATCH] Add 400 retry --- src/pkg/services/m365/api/graph/errors.go | 11 ++++++++++- src/pkg/services/m365/api/graph/middleware.go | 5 +++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/pkg/services/m365/api/graph/errors.go b/src/pkg/services/m365/api/graph/errors.go index c84bfcc98..6c8cd51fb 100644 --- a/src/pkg/services/m365/api/graph/errors.go +++ b/src/pkg/services/m365/api/graph/errors.go @@ -52,7 +52,8 @@ const ( // This error occurs when an attempt is made to create a folder that has // the same name as another folder in the same parent. Such duplicate folder // names are not allowed by graph. - folderExists errorCode = "ErrorFolderExists" + folderExists errorCode = "ErrorFolderExists" + invalidRequest errorCode = "invalidRequest" // Some datacenters are returning this when we try to get the inbox of a user // that doesn't exist. invalidUser errorCode = "ErrorInvalidUser" @@ -140,6 +141,14 @@ var ( ErrTokenExpired = clues.New("jwt token expired") ) +// IsErrInvalidRequest is to retry transient graph 400 errors with odata error code +// set to invalidRequest. +func IsErrInvalidRequest(err error, resp *http.Response) bool { + return resp != nil && + resp.StatusCode == http.StatusBadRequest && + parseODataErr(err).hasErrorCode(err, invalidRequest) +} + func IsErrApplicationThrottled(err error) bool { return errors.Is(err, ErrApplicationThrottled) || parseODataErr(err).hasErrorCode(err, applicationThrottled) diff --git a/src/pkg/services/m365/api/graph/middleware.go b/src/pkg/services/m365/api/graph/middleware.go index 3405c030c..c8493c7b1 100644 --- a/src/pkg/services/m365/api/graph/middleware.go +++ b/src/pkg/services/m365/api/graph/middleware.go @@ -161,7 +161,8 @@ func (mw RetryMiddleware) Intercept( retriable := IsErrTimeout(err) || IsErrConnectionReset(err) || - mw.isRetriableRespCode(ctx, resp) + mw.isRetriableRespCode(ctx, resp) || + IsErrInvalidRequest(err, resp) if !retriable { return resp, stackReq(ctx, req, resp, err).OrNil() @@ -206,7 +207,7 @@ func (mw RetryMiddleware) retryRequest( // 1, there was a prior error OR the status code match retriable conditions. // 3, the request method is retriable. // 4, we haven't already hit maximum retries. - shouldRetry := (priorErr != nil || mw.isRetriableRespCode(ctx, resp)) && + shouldRetry := (priorErr != nil || mw.isRetriableRespCode(ctx, resp) || IsErrInvalidRequest(priorErr, resp)) && mw.isRetriableRequest(req) && executionCount < mw.MaxRetries