Add HTTP upload idempotency support

This commit is contained in:
2026-06-04 14:03:26 +00:00
parent 1a402e6cfa
commit a15722571f
9 changed files with 603 additions and 36 deletions

View File

@@ -30,6 +30,14 @@ Returns `200 OK` when the server is running:
Accepts one source bundle archive and returns after the archive is staged and validated.
Producers may include:
```text
Idempotency-Key: <key>
```
Idempotency keys are scoped to the authenticated pipeline selected by the bearer token. Valid keys are non-empty ASCII strings up to 128 bytes using letters, digits, `.`, `_`, `-`, and `:`. Invalid keys return `400`.
Accepted content types:
- `application/x-tar`
@@ -44,8 +52,9 @@ Successful admission returns `202 Accepted`:
Common error responses:
- `400`: pipeline query supplied, archive rejected, malformed archive, or invalid staged source bundle.
- `400`: pipeline query supplied, invalid idempotency key, archive rejected, malformed archive, or invalid staged source bundle.
- `401`: missing, empty, or unknown bearer token.
- `409`: repeated idempotency key conflicts with another source manifest, or the same key is already being staged.
- `413`: upload body exceeds the selected pipeline size limit.
- `415`: unsupported content type.
- `503`: upload queue is full.
@@ -56,6 +65,14 @@ Error bodies use:
{"error":"<message>"}
```
Retryable idempotency conflicts include:
```json
{"error":"upload idempotency key is already being processed","retryable":true}
```
When `Idempotency-Key` is omitted, upload admission preserves the raw HTTP behavior: every valid accepted upload receives its own run id. When a key is supplied, the server records the accepted run after archive staging and source bundle validation succeed. Reusing the same key for the same authenticated pipeline and the same normalized source manifest returns the original `202 Accepted` response and does not enqueue another run. Reusing the same key for a different normalized source manifest returns `409 Conflict`.
### `GET /runs/<run-id>`
Returns an in-memory status record while retained:
@@ -95,6 +112,8 @@ The uploaded archive size and extracted bundle size are bounded by the selected
Completed status records expire after `server.http.retention`; expiration removes committed staged bundle directories for completed uploads. Server restart clears queue state and status records.
Idempotency records are memory-only, expire with completed upload status records, and are cleared by server restart.
## Boundaries
The HTTP API does not expose pipeline selection by request parameter, TLS, public routing policy, or durable status storage. Put public access controls, TLS termination, and rate limiting in deployment infrastructure.