formalizes ErrApplicationThrottled (#4317)
adds graph error identification for application throttled and adds an ApplicationThrottled sentinel to pkg/errs for sdk consumer identification. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🌻 Feature #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
b212c37fd3
commit
c1ec3c6648
@ -26,6 +26,7 @@ import (
|
|||||||
type errorCode string
|
type errorCode string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
applicationThrottled errorCode = "ApplicationThrottled"
|
||||||
// this auth error is a catch-all used by graph in a variety of cases:
|
// this auth error is a catch-all used by graph in a variety of cases:
|
||||||
// users without licenses, bad jwts, missing account permissions, etc.
|
// users without licenses, bad jwts, missing account permissions, etc.
|
||||||
AuthenticationError errorCode = "AuthenticationError"
|
AuthenticationError errorCode = "AuthenticationError"
|
||||||
@ -81,6 +82,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// ErrApplicationThrottled occurs if throttling retries are exhausted and completely
|
||||||
|
// fails out.
|
||||||
|
ErrApplicationThrottled = clues.New("application throttled")
|
||||||
|
|
||||||
// The folder or item was deleted between the time we identified
|
// The folder or item was deleted between the time we identified
|
||||||
// it and when we tried to fetch data for it.
|
// it and when we tried to fetch data for it.
|
||||||
ErrDeletedInFlight = clues.New("deleted in flight")
|
ErrDeletedInFlight = clues.New("deleted in flight")
|
||||||
@ -116,6 +121,11 @@ var (
|
|||||||
ErrResourceOwnerNotFound = clues.New("resource owner not found in tenant")
|
ErrResourceOwnerNotFound = clues.New("resource owner not found in tenant")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func IsErrApplicationThrottled(err error) bool {
|
||||||
|
return hasErrorCode(err, applicationThrottled) ||
|
||||||
|
errors.Is(err, ErrApplicationThrottled)
|
||||||
|
}
|
||||||
|
|
||||||
func IsErrAuthenticationError(err error) bool {
|
func IsErrAuthenticationError(err error) bool {
|
||||||
return hasErrorCode(err, AuthenticationError)
|
return hasErrorCode(err, AuthenticationError)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,6 +94,40 @@ func (suite *GraphErrorsUnitSuite) TestIsErrConnectionReset() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *GraphErrorsUnitSuite) TestIsErrApplicationThrottled() {
|
||||||
|
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: "non-matching oDataErr",
|
||||||
|
err: odErr("fnords"),
|
||||||
|
expect: assert.False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "applicationThrottled oDataErr",
|
||||||
|
err: odErr(string(applicationThrottled)),
|
||||||
|
expect: assert.True,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range table {
|
||||||
|
suite.Run(test.name, func() {
|
||||||
|
test.expect(suite.T(), IsErrApplicationThrottled(test.err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *GraphErrorsUnitSuite) TestIsErrAuthenticationError() {
|
func (suite *GraphErrorsUnitSuite) TestIsErrAuthenticationError() {
|
||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@ -113,6 +113,10 @@ func (hw httpWrapper) Request(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if IsErrApplicationThrottled(err) {
|
||||||
|
return nil, Stack(ictx, clues.Stack(ErrApplicationThrottled, err))
|
||||||
|
}
|
||||||
|
|
||||||
var http2StreamErr http2.StreamError
|
var http2StreamErr http2.StreamError
|
||||||
if !errors.As(err, &http2StreamErr) {
|
if !errors.As(err, &http2StreamErr) {
|
||||||
return nil, Stack(ictx, err)
|
return nil, Stack(ictx, err)
|
||||||
|
|||||||
@ -360,6 +360,10 @@ func (aw *adapterWrap) Send(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if IsErrApplicationThrottled(err) {
|
||||||
|
return nil, clues.Stack(ErrApplicationThrottled, err).WithTrace(1).WithClues(ictx)
|
||||||
|
}
|
||||||
|
|
||||||
if !IsErrConnectionReset(err) && !connectionEnded.Compare(err.Error()) {
|
if !IsErrConnectionReset(err) && !connectionEnded.Compare(err.Error()) {
|
||||||
return nil, clues.Stack(err).WithTrace(1).WithClues(ictx)
|
return nil, clues.Stack(err).WithTrace(1).WithClues(ictx)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,20 +13,22 @@ import (
|
|||||||
type errEnum string
|
type errEnum string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RepoAlreadyExists errEnum = "repository-already-exists"
|
ApplicationThrottled errEnum = "application-throttled"
|
||||||
BackupNotFound errEnum = "backup-not-found"
|
BackupNotFound errEnum = "backup-not-found"
|
||||||
ServiceNotEnabled errEnum = "service-not-enabled"
|
RepoAlreadyExists errEnum = "repository-already-exists"
|
||||||
ResourceOwnerNotFound errEnum = "resource-owner-not-found"
|
ResourceOwnerNotFound errEnum = "resource-owner-not-found"
|
||||||
|
ServiceNotEnabled errEnum = "service-not-enabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
// map of enums to errors. We might want to re-use an enum for multiple
|
// map of enums to errors. We might want to re-use an enum for multiple
|
||||||
// internal errors (ex: "ServiceNotEnabled" may exist in both graph and
|
// internal errors (ex: "ServiceNotEnabled" may exist in both graph and
|
||||||
// non-graph producers).
|
// non-graph producers).
|
||||||
var internalToExternal = map[errEnum][]error{
|
var internalToExternal = map[errEnum][]error{
|
||||||
RepoAlreadyExists: {repository.ErrorRepoAlreadyExists},
|
ApplicationThrottled: {graph.ErrApplicationThrottled},
|
||||||
BackupNotFound: {repository.ErrorBackupNotFound},
|
BackupNotFound: {repository.ErrorBackupNotFound},
|
||||||
ServiceNotEnabled: {graph.ErrServiceNotEnabled},
|
RepoAlreadyExists: {repository.ErrorRepoAlreadyExists},
|
||||||
ResourceOwnerNotFound: {graph.ErrResourceOwnerNotFound},
|
ResourceOwnerNotFound: {graph.ErrResourceOwnerNotFound},
|
||||||
|
ServiceNotEnabled: {graph.ErrServiceNotEnabled},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal returns the internal errors which match to the public error category.
|
// Internal returns the internal errors which match to the public error category.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user