mirror of
https://github.com/nextcloud/server.git
synced 2026-04-27 17:18:48 -04:00
Merge pull request #53419 from nextcloud/leftybournes/fix/object_storage_large_uploads
fix(s3): retry failed multipart uploads with decreased concurrency
This commit is contained in:
commit
ea98e4b3f5
1 changed files with 43 additions and 17 deletions
|
|
@ -119,28 +119,54 @@ trait S3ObjectTrait {
|
|||
protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void {
|
||||
$mimetype = $metaData['mimetype'] ?? null;
|
||||
unset($metaData['mimetype']);
|
||||
$uploader = new MultipartUploader($this->getConnection(), $stream, [
|
||||
'bucket' => $this->bucket,
|
||||
'concurrency' => $this->concurrency,
|
||||
'key' => $urn,
|
||||
'part_size' => $this->uploadPartSize,
|
||||
'params' => [
|
||||
'ContentType' => $mimetype,
|
||||
'Metadata' => $this->buildS3Metadata($metaData),
|
||||
'StorageClass' => $this->storageClass,
|
||||
] + $this->getSSECParameters(),
|
||||
]);
|
||||
|
||||
try {
|
||||
$uploader->upload();
|
||||
} catch (S3MultipartUploadException $e) {
|
||||
$attempts = 0;
|
||||
$uploaded = false;
|
||||
$concurrency = $this->concurrency;
|
||||
$exception = null;
|
||||
$state = null;
|
||||
|
||||
// retry multipart upload once with concurrency at half on failure
|
||||
while (!$uploaded && $attempts <= 1) {
|
||||
$uploader = new MultipartUploader($this->getConnection(), $stream, [
|
||||
'bucket' => $this->bucket,
|
||||
'concurrency' => $concurrency,
|
||||
'key' => $urn,
|
||||
'part_size' => $this->uploadPartSize,
|
||||
'state' => $state,
|
||||
'params' => [
|
||||
'ContentType' => $mimetype,
|
||||
'Metadata' => $this->buildS3Metadata($metaData),
|
||||
'StorageClass' => $this->storageClass,
|
||||
] + $this->getSSECParameters(),
|
||||
]);
|
||||
|
||||
try {
|
||||
$uploader->upload();
|
||||
$uploaded = true;
|
||||
} catch (S3MultipartUploadException $e) {
|
||||
$exception = $e;
|
||||
$attempts++;
|
||||
|
||||
if ($concurrency > 1) {
|
||||
$concurrency = round($concurrency / 2);
|
||||
}
|
||||
|
||||
if ($stream->isSeekable()) {
|
||||
$stream->rewind();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$uploaded) {
|
||||
// if anything goes wrong with multipart, make sure that you don´t poison and
|
||||
// slow down s3 bucket with orphaned fragments
|
||||
$uploadInfo = $e->getState()->getId();
|
||||
if ($e->getState()->isInitiated() && (array_key_exists('UploadId', $uploadInfo))) {
|
||||
$uploadInfo = $exception->getState()->getId();
|
||||
if ($exception->getState()->isInitiated() && (array_key_exists('UploadId', $uploadInfo))) {
|
||||
$this->getConnection()->abortMultipartUpload($uploadInfo);
|
||||
}
|
||||
throw new \OCA\DAV\Connector\Sabre\Exception\BadGateway('Error while uploading to S3 bucket', 0, $e);
|
||||
|
||||
throw new \OCA\DAV\Connector\Sabre\Exception\BadGateway('Error while uploading to S3 bucket', 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue