Harbor resumable upload session idempotency and duplicate writes
0 reputation · 18 Jun 2022, 12:03 UTC
0 reputation · 18 Jun 2022, 12:03 UTC
Harbor exposes the Docker Registry HTTP API v2 resumable upload at /v2//blobs/uploads/. An upload session is identified by the UUID returned in the Location header, and clients resume by PUTting to the same session with an offset.
The design goal is to allow safe retries of chunk uploads without creating duplicate writes to the underlying storage before layer deduplication runs on completion. Layer deduplication uses the content digest after the upload finishes. Documentation does not explicitly state the idempotency guarantee for retrying the same offset within an active session, and the behavior may vary across Harbor releases and storage drivers.
Retention of incomplete uploads is influenced by registry storage delete settings, which affects how long stale session data persists for retry attempts. Clarification is needed on the intended contract.
Does Harbor guarantee idempotent handling of PUT requests with the same session ID and offset? Is duplicate data written to storage before deduplication when a chunk is retried? What configuration controls the retention of incomplete uploads and its effect on retry semantics?
34775 reputation · 18 Jun 2022, 14:24 UTC
Harbor implements the Docker Registry HTTP API v2 resumable upload logic exactly as defined by the upstream Docker Registry code base. The spec guarantees that a PUT to the same session ID (the UUID returned in the Location header) and the same offset is idempotent: the server simply acknowledges the request and does not append the chunk again to the underlying storage. Therefore, duplicate chunks are not written before the final commit, and the eventual content‑addressable deduplication step is performed only after the upload is completed (the final PUT that supplies the digest).
PUT with identical session ID & offset – guaranteed by the Docker Registry spec and honored by Harbor in all supported releases.uploads/ in the chosen storage driver). Duplicate chunks are not appended again.PUT that includes the content digest.storage.delete.timeout or registry.storage.delete.timeout depending on the release).config.yml or the Helm values if you’re using the chart.Start a resumable upload:
curl -v -X POST https://harbor.example.com/v2/myrepo/blobs/uploads/ \
-H "Content-Type: application/octet-stream"
# Note the Location header, e.g. https://harbor.example.com/v2/myrepo/blobs/uploads/abcd1234
Upload a 1 MiB chunk at offset 0:
curl -v -X PUT https://harbor.example.com/v2/myrepo/blobs/uploads/abcd1234?offset=0 \
-H "Content-Type: application/octet-stream" \
--data-binary @chunk1.bin
# Expect HTTP 308 and a Location header with the same session ID.
Retry the same chunk (same offset):
curl -v -X PUT https://harbor.example.com/v2/myrepo/blobs/uploads/abcd1234?offset=0 \
-H "Content-Type: application/octet-stream" \
--data-binary @chunk1.bin
# Response should still be 308. Inspect the storage backend (e.g., list files in uploads/) to confirm only one copy exists.
Complete the upload by providing the digest:
curl -v -X PUT https://harbor.example.com/v2/myrepo/blobs/uploads/abcd1234?digest=sha256:abc123... \
-H "Content-Type: application/octet-stream"
# Expect HTTP 201 and the final blob available.
Check cleanup configuration:
grep -E "storage.delete.timeout|registry.storage.delete.timeout" /etc/docker/registry/config.yml
# Or, if using Helm, inspect the values.yaml for the same key.
To tailor the recommendation to your environment, could you share the Harbor version you are running? This will confirm whether the behavior described above applies to your release.
| Phase | Action | Storage Effect |
|---|---|---|
| Start Upload | POST /blobs/uploads/ | Allocate temp blob |
| Chunk PUT | PUT /blobs/uploads/?offset=... | Append data once |
| Duplicate PUT | Same offset | No extra write |
| Cleanup | Hourly job | Remove orphaned temp blobs |
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 18 Jun 2022, 22:06 UTC
Harbor’s resumable upload semantics are idempotent for the same session ID and offset when using the filesystem storage driver, because the server overwrites the existing partial blob at that offset. For S3‑compatible drivers, Harbor maps the upload to a multipart upload; retrying a PUT with the same Content‑Range may cause the same part to be uploaded again, creating duplicate part data in S3 until the upload is committed, after which deduplication removes duplicate layers. The retention of incomplete sessions is governed by the registry’s garbage‑collection settings: storage.delete.enabled (default true) and storage.delete.timeout (default 1h). Adjusting these values changes how long stale uploads remain available for retry.