(PTFE-3070) Add multi part upload for large file#576
Conversation
b08f5a3 to
24b487f
Compare
Review by Claude Code |
Review by Claude Code |
|
The multipart upload implementation is well-structured: proper abort on failure to avoid orphaned S3 parts, presigned URLs re-fetched on each retry attempt (handling expiry), resource cleanup via Review by Claude Code |
Review by Claude Code |
Transient 5xx errors (e.g. 502 Bad Gateway) on a single multipart part caused the entire upload to abort with no recovery. fileUploadMultipart now retries each part independently (up to 10 times with exponential backoff) before aborting the multipart session. The same retry wrapper is applied to fileUploadPresigned, which had the same gap vs the legacy fileUpload path that already used artifactsRetry(client, 10). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 5 min timeout to raw https.request calls in fileUploadPresigned and uploadPart (multipart): a stalled S3 connection would otherwise hang the action until the 6h GitHub Actions workflow timeout. The 'timeout' option only emits an event; req.destroy() is needed to actually abort the socket. - Wrap multipart initiate and complete in retryWithBackoff: a transient failure on initiate aborts before any upload starts; a failure on complete wastes all uploaded parts (the abort handler only covers the parts-upload phase, not the finish line). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The three arrow functions passed to retryWithBackoff returned Promises without being declared async, triggering the @typescript-eslint/promise-function-async rule. Also apply prettier reformatting picked up by the format step. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n complete failure - retryWithBackoff: skip retry on AxiosError with status < 500. Auth failures (401/403) were being retried 10 times with ~100s of exponential backoff before surfacing. Only 5xx and network errors are transient and worth retrying. - fileUploadPresigned / uploadPart: wrap the S3 https.request in try/finally with stream.destroy(). Without this, each failed attempt leaves an open ReadStream/FD until GC — up to 10 leaks per file. - fileUploadMultipart: move the complete POST inside the existing try block so the catch handler aborts the multipart upload when complete fails after exhausting retries. Previously, parts would be left orphaned on S3 indefinitely if complete failed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 8-file limit was chosen to cap peak S3 connections at 8×4=32 when multipart is active. For workloads with only small files (< 100 MB), each file uses one connection regardless, so the cap halved throughput for no benefit. Inspect the file list before uploading: if no file exceeds MULTIPART_THRESHOLD (or if multipart is not supported), use 16 concurrent file uploads instead of 8 to match the previous behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| value: ${{ steps.artifacts.outputs.redirect-link }} | ||
| runs: | ||
| using: 'node20' | ||
| using: 'node24' |
There was a problem hiding this comment.
Breaking change: node20 → node24 changes the runtime for every consumer of this action. Workflows running on self-hosted runners without Node.js 24 will fail. This is independent of the multipart upload feature and should be called out in the PR description and release notes so callers know to expect a runtime change.
— Claude Code
| } | ||
| } | ||
| await Promise.all( | ||
| Array.from({length: Math.min(MULTIPART_CONCURRENCY, partCount)}, worker) |
There was a problem hiding this comment.
When one worker rejects, Promise.all rejects immediately but the remaining workers continue running. Their eventual rejections become unhandled promise rejections, which in Node.js 24 defaults to crashing the process (--unhandled-rejections=throw). Consider using Promise.allSettled and rethrowing the first failure so all worker promises settle cleanly before the catch block aborts the upload.
— Claude Code
|
When GITHUB_RUN_ATTEMPT > 1, fileVersion backs up the previous file before overwriting it. If versioning fails (transient S3 error, or the file was never uploaded in a prior attempt), the upload was being blocked entirely, preventing re-runs from succeeding. Make versioning non-fatal: log a warning and proceed with the upload so that re-runs always make progress regardless of whether the backup step succeeded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| value: ${{ steps.artifacts.outputs.redirect-link }} | ||
| runs: | ||
| using: 'node20' | ||
| using: 'node24' |
There was a problem hiding this comment.
Breaking change: switching the action runtime from node20 to node24 affects every caller. Node.js 24 is still in Current (not LTS). Self-hosted runners without node24 installed will fail. This should be called out as a breaking change in the PR description.
— Claude Code
|
This pull request updates the GitHub Actions workflows to use the latest
actions/checkout@v6and introduces improved multipart upload support for large files in the artifact upload action. It also updates the test workflows to cover the multipart upload path, and updates the container image reference forartifacts. These changes improve compatibility, performance, and test coverage.Workflow and Dependency Updates:
All workflows now use
actions/checkout@v6instead of older versions, ensuring compatibility and access to the latest features and security updates. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21]The
artifactscontainer image intest-promote.yamlis updated fromregistry.scality.com/artifacts/artifacts:4.2.6toghcr.io/scality/artifacts:4.3.3, ensuring the use of the latest image from GitHub Container Registry.Multipart Upload Support:
Added multipart upload support for files larger than 100 MB in
src/artifacts.ts, with each part set to 64 MB and up to 4 parts uploaded concurrently. This improves reliability and performance for large file uploads.A new test job,
test-upload-multipart, is added totest-upload.yamlto verify multipart upload functionality and ensure file integrity for files above the 100 MB threshold.The artifact upload workflow dependencies are updated to include the new multipart upload test, ensuring it runs as part of the CI process.
These changes collectively modernize the CI workflows and strengthen support for large artifact uploads.