swift: Change retry_403 to retry_errors option

This commit is contained in:
Bohdan Horbeshko 2024-07-30 13:57:35 +03:00
parent bb86f466b0
commit d4a7716661
1 changed files with 31 additions and 27 deletions

View File

@ -315,11 +315,12 @@ Reduce this if you have errors with listing large directories.`,
Default: 1000,
Advanced: true,
}, {
Name: "retry_403",
Help: `Retry on 403 errors.
Name: "retry_errors",
Help: `Additional comma-separated list of error codes to retry on.
Blomp is known to return 403 errors on directory listing requests.`,
Default: false,
Blomp is known to return arbitrary errors on directory listing requests.
Known ones are 400, 403 and 404.`,
Default: fs.CommaSepList{},
Advanced: true,
}}, SharedOptions...),
})
@ -354,7 +355,7 @@ type Options struct {
FetchUntilEmptyPage bool `config:"fetch_until_empty_page"`
PartialPageFetchThreshold int `config:"partial_page_fetch_threshold"`
ListChunks int `config:"list_chunks"`
Retry403 bool `config:"retry_403"`
RetryErrors fs.CommaSepList `config:"retry_errors"`
}
// Fs represents a remote swift server
@ -426,7 +427,7 @@ var retryErrorCodes = []int{
// shouldRetry returns a boolean as to whether this err deserves to be
// retried. It returns the err as a convenience
func shouldRetry(ctx context.Context, err error, retry403 bool) (bool, error) {
func shouldRetry(ctx context.Context, err error, retryErrors fs.CommaSepList) (bool, error) {
if fserrors.ContextError(ctx, &err) {
return false, err
}
@ -437,8 +438,11 @@ func shouldRetry(ctx context.Context, err error, retry403 bool) (bool, error) {
return true, err
}
}
if retry403 && swiftError.StatusCode == 403 {
return true, err
for _, code := range retryErrors {
intCode, intError := strconv.Atoi(code)
if intError == nil && swiftError.StatusCode == intCode {
return true, err
}
}
}
// Check for generic failure conditions
@ -448,7 +452,7 @@ func shouldRetry(ctx context.Context, err error, retry403 bool) (bool, error) {
// shouldRetryHeaders returns a boolean as to whether this err
// deserves to be retried. It reads the headers passed in looking for
// `Retry-After`. It returns the err as a convenience
func shouldRetryHeaders(ctx context.Context, headers swift.Headers, err error, retry403 bool) (bool, error) {
func shouldRetryHeaders(ctx context.Context, headers swift.Headers, err error, retryErrors fs.CommaSepList) (bool, error) {
if swiftError, ok := err.(*swift.Error); ok && swiftError.StatusCode == 429 {
if value := headers["Retry-After"]; value != "" {
retryAfter, parseErr := strconv.Atoi(value)
@ -467,7 +471,7 @@ func shouldRetryHeaders(ctx context.Context, headers swift.Headers, err error, r
}
}
}
return shouldRetry(ctx, err, retry403)
return shouldRetry(ctx, err, retryErrors)
}
// parsePath parses a remote 'url'
@ -616,7 +620,7 @@ func NewFsWithConnection(ctx context.Context, opt *Options, name, root string, c
err = f.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
info, rxHeaders, err = f.c.Object(ctx, f.rootContainer, encodedDirectory)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.RetryErrors)
})
if err == nil && info.ContentType != directoryMarkerContentType {
newRoot := path.Dir(f.root)
@ -724,7 +728,7 @@ func (f *Fs) listContainerRoot(ctx context.Context, container, directory, prefix
var err error
err = f.pacer.Call(func() (bool, error) {
objects, err = f.c.Objects(ctx, container, opts)
return shouldRetry(ctx, err, f.opt.Retry403)
return shouldRetry(ctx, err, f.opt.RetryErrors)
})
if err == nil {
for i := range objects {
@ -813,7 +817,7 @@ func (f *Fs) listContainers(ctx context.Context) (entries fs.DirEntries, err err
var containers []swift.Container
err = f.pacer.Call(func() (bool, error) {
containers, err = f.c.ContainersAll(ctx, nil)
return shouldRetry(ctx, err, f.opt.Retry403)
return shouldRetry(ctx, err, f.opt.RetryErrors)
})
if err != nil {
return nil, fmt.Errorf("container listing failed: %w", err)
@ -906,7 +910,7 @@ func (f *Fs) About(ctx context.Context) (usage *fs.Usage, err error) {
var container swift.Container
err = f.pacer.Call(func() (bool, error) {
container, _, err = f.c.Container(ctx, f.rootContainer)
return shouldRetry(ctx, err, f.opt.Retry403)
return shouldRetry(ctx, err, f.opt.RetryErrors)
})
if err != nil {
return nil, fmt.Errorf("container info failed: %w", err)
@ -917,7 +921,7 @@ func (f *Fs) About(ctx context.Context) (usage *fs.Usage, err error) {
var containers []swift.Container
err = f.pacer.Call(func() (bool, error) {
containers, err = f.c.ContainersAll(ctx, nil)
return shouldRetry(ctx, err, f.opt.Retry403)
return shouldRetry(ctx, err, f.opt.RetryErrors)
})
if err != nil {
return nil, fmt.Errorf("container listing failed: %w", err)
@ -969,7 +973,7 @@ func (f *Fs) makeContainer(ctx context.Context, container string) error {
err = f.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
_, rxHeaders, err = f.c.Container(ctx, container)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.RetryErrors)
})
}
if err == swift.ContainerNotFound {
@ -979,7 +983,7 @@ func (f *Fs) makeContainer(ctx context.Context, container string) error {
}
err = f.pacer.Call(func() (bool, error) {
err = f.c.ContainerCreate(ctx, container, headers)
return shouldRetry(ctx, err, f.opt.Retry403)
return shouldRetry(ctx, err, f.opt.RetryErrors)
})
if err == nil {
fs.Infof(f, "Container %q created", container)
@ -1000,7 +1004,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error {
err := f.cache.Remove(container, func() error {
err := f.pacer.Call(func() (bool, error) {
err := f.c.ContainerDelete(ctx, container)
return shouldRetry(ctx, err, f.opt.Retry403)
return shouldRetry(ctx, err, f.opt.RetryErrors)
})
if err == nil {
fs.Infof(f, "Container %q removed", container)
@ -1078,7 +1082,7 @@ func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object,
err = f.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
rxHeaders, err = f.c.ObjectCopy(ctx, srcContainer, srcPath, dstContainer, dstPath, nil)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.RetryErrors)
})
}
if err != nil {
@ -1173,7 +1177,7 @@ func (su *segmentedUpload) uploadManifest(ctx context.Context, contentType strin
err = su.f.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
rxHeaders, err = su.f.c.ObjectPut(ctx, su.dstContainer, su.dstPath, emptyReader, true, "", contentType, headers)
return shouldRetryHeaders(ctx, rxHeaders, err, su.f.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, su.f.opt.RetryErrors)
})
return err
}
@ -1197,7 +1201,7 @@ func (f *Fs) copyLargeObject(ctx context.Context, src *Object, dstContainer stri
err = f.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
rxHeaders, err = f.c.ObjectCopy(ctx, srcSegmentsContainer, srcSegment, su.container, dstSegment, nil)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, f.opt.RetryErrors)
})
if err != nil {
return err
@ -1344,7 +1348,7 @@ func (o *Object) readMetaData(ctx context.Context) (err error) {
container, containerPath := o.split()
err = o.fs.pacer.Call(func() (bool, error) {
info, h, err = o.fs.c.Object(ctx, container, containerPath)
return shouldRetryHeaders(ctx, h, err, o.fs.opt.Retry403)
return shouldRetryHeaders(ctx, h, err, o.fs.opt.RetryErrors)
})
if err != nil {
if err == swift.ObjectNotFound {
@ -1402,7 +1406,7 @@ func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
container, containerPath := o.split()
return o.fs.pacer.Call(func() (bool, error) {
err = o.fs.c.ObjectUpdate(ctx, container, containerPath, newHeaders)
return shouldRetry(ctx, err, o.fs.opt.Retry403)
return shouldRetry(ctx, err, o.fs.opt.RetryErrors)
})
}
@ -1423,7 +1427,7 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.Read
err = o.fs.pacer.Call(func() (bool, error) {
var rxHeaders swift.Headers
in, rxHeaders, err = o.fs.c.ObjectOpen(ctx, container, containerPath, !isRanging, headers)
return shouldRetryHeaders(ctx, rxHeaders, err, o.fs.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, o.fs.opt.RetryErrors)
})
return
}
@ -1515,7 +1519,7 @@ func (o *Object) updateChunks(ctx context.Context, in0 io.Reader, headers swift.
err = o.fs.pacer.CallNoRetry(func() (bool, error) {
var rxHeaders swift.Headers
rxHeaders, err = o.fs.c.ObjectPut(ctx, su.container, segmentPath, segmentReader, true, "", "", headers)
return shouldRetryHeaders(ctx, rxHeaders, err, o.fs.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, o.fs.opt.RetryErrors)
})
if err != nil {
return err
@ -1579,7 +1583,7 @@ func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, op
var rxHeaders swift.Headers
err = o.fs.pacer.CallNoRetry(func() (bool, error) {
rxHeaders, err = o.fs.c.ObjectPut(ctx, container, containerPath, in, true, "", contentType, headers)
return shouldRetryHeaders(ctx, rxHeaders, err, o.fs.opt.Retry403)
return shouldRetryHeaders(ctx, rxHeaders, err, o.fs.opt.RetryErrors)
})
if err != nil {
return err
@ -1644,7 +1648,7 @@ func (o *Object) Remove(ctx context.Context) (err error) {
fs.Errorf(o, "Dangling object - ignoring: %v", err)
err = nil
}
return shouldRetry(ctx, err, o.fs.opt.Retry403)
return shouldRetry(ctx, err, o.fs.opt.RetryErrors)
})
if err != nil {
return err