mirror of
https://github.com/rclone/rclone.git
synced 2026-06-19 19:04:02 +02:00
yandex: fix 500 errors by waiting for uploads to complete before setting modtime
After PUTting a file to the upload URL, Yandex keeps the file locked for writing until the upload operation finishes committing on the server. The PUT returned before this happened, so the following SetModTime (and any listing) raced the still-in-progress write and got spurious 500 Internal Server Error responses. Capture the operation_id returned with the upload URL and poll the operation status until it reports success before returning, so the file is fully committed before we touch it.
This commit is contained in:
@@ -52,9 +52,10 @@ type ResourceListResponse struct {
|
||||
|
||||
// AsyncInfo struct is returned by the API for various async operations.
|
||||
type AsyncInfo struct {
|
||||
HRef string `json:"href"`
|
||||
Method string `json:"method"`
|
||||
Templated bool `json:"templated"`
|
||||
HRef string `json:"href"`
|
||||
Method string `json:"method"`
|
||||
Templated bool `json:"templated"`
|
||||
OperationID string `json:"operation_id"`
|
||||
}
|
||||
|
||||
// AsyncStatus is returned when requesting the status of an async operations. Possible values in-progress, success, failure
|
||||
|
||||
@@ -577,7 +577,7 @@ func (f *Fs) waitForJob(ctx context.Context, location string) (err error) {
|
||||
}
|
||||
|
||||
switch status.Status {
|
||||
case "failure":
|
||||
case "failure", "failed":
|
||||
return fmt.Errorf("async operation returned %q", status.Status)
|
||||
case "success":
|
||||
return nil
|
||||
@@ -1124,6 +1124,17 @@ func (o *Object) upload(ctx context.Context, in io.Reader, overwrite bool, mimeT
|
||||
resp, err = o.fs.srv.Call(ctx, &opts)
|
||||
return shouldRetry(ctx, resp, err)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The PUT returns before Yandex has finished committing the file
|
||||
// to disk - the file remains locked for writing until the upload
|
||||
// operation reports success. Wait for it so that a following
|
||||
// SetModTime (or list) doesn't race the write and get a 500.
|
||||
if ur.OperationID != "" {
|
||||
err = o.fs.waitForJob(ctx, rootURL+"/operations/"+ur.OperationID)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user