retry on "connection reset by peer" (#3138)

retry when we receive a "connection reset by peer" error

---

#### Does this PR need a docs update or release note?

- [x]  Yes, it's included

#### Type of change

- [x] 🐛 Bugfix

#### Issue(s)

* #3129

#### Test Plan

- [x] 💪 Manual
- [x]  Unit test
This commit is contained in:
Keepers 2023-04-19 12:51:29 -06:00 committed by GitHub
parent 5166e61115
commit 09ef350bc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 37 additions and 1 deletions

View File

@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Skip OneNote items bigger than 2GB (Graph API prevents us from downloading them)
- ParentPath of json output for Exchange calendar now shows names instead of IDs.
- Fixed failure when downloading huge amount of attachments
- Graph API requests that return an ECONNRESET error are now retried.
### Known Issues
- Restoring a OneDrive or SharePoint file with the same name as a file with that name as its M365 ID may restore both items.

View File

@ -8,6 +8,7 @@ import (
"net/url"
"os"
"strings"
"syscall"
"github.com/alcionai/clues"
"github.com/microsoftgraph/msgraph-sdk-go/models"
@ -116,6 +117,10 @@ func IsErrTimeout(err error) bool {
os.IsTimeout(err)
}
func IsErrConnectionReset(err error) bool {
return errors.Is(err, syscall.ECONNRESET)
}
func IsErrUnauthorized(err error) bool {
// TODO: refine this investigation. We don't currently know if
// a specific item download url expired, or if the full connection

View File

@ -3,6 +3,7 @@ package graph
import (
"context"
"net/http"
"syscall"
"testing"
"github.com/alcionai/clues"
@ -32,6 +33,35 @@ func odErr(code string) *odataerrors.ODataError {
return odErr
}
func (suite *GraphErrorsUnitSuite) TestIsErrConnectionReset() {
table := []struct {
name string
err error
expect assert.BoolAssertionFunc
}{
{
name: "nil",
err: nil,
expect: assert.False,
},
{
name: "non-matching",
err: assert.AnError,
expect: assert.False,
},
{
name: "matching",
err: syscall.ECONNRESET,
expect: assert.True,
},
}
for _, test := range table {
suite.Run(test.name, func() {
test.expect(suite.T(), IsErrConnectionReset(test.err))
})
}
}
func (suite *GraphErrorsUnitSuite) TestIsErrDeletedInFlight() {
table := []struct {
name string

View File

@ -213,7 +213,7 @@ func (middleware RetryHandler) retryRequest(
}
response, err := pipeline.Next(req, middlewareIndex)
if err != nil && !IsErrTimeout(err) {
if err != nil && !IsErrTimeout(err) && !IsErrConnectionReset(err) {
return response, Stack(ctx, err).With("retry_count", executionCount)
}