212 lines
7.8 KiB
Markdown
212 lines
7.8 KiB
Markdown
# Producer HTTP Upload Package Implementation Roadmap
|
|
|
|
## Current Baseline
|
|
|
|
`distributor serve` and the `http_upload` source backend are implemented.
|
|
Producers can already submit complete tar or gzip-compressed tar source bundles
|
|
to `POST /upload` with bearer authentication, and each bearer token maps to one
|
|
configured upload pipeline.
|
|
|
|
The public `pkg/bundle` package already provides producer-side source manifest
|
|
semantics, digest calculation, path validation, local manifest building, local
|
|
bundle writing, and local bundle validation helpers.
|
|
|
|
The current implementation does not have a server-side producer idempotency
|
|
contract, and it does not provide a public `pkg/upload` helper package.
|
|
|
|
Future behavior remains under `docs/roadmap/` until implemented. Do not update
|
|
README, current user docs, examples, or current-behavior internal docs until the
|
|
corresponding stage has been implemented.
|
|
|
|
This active roadmap implements the accepted producer upload package plan in
|
|
`docs/roadmap/producer.md`. It supersedes the older `docs/roadmap/http.md`
|
|
deferred note for producer-supplied idempotency keys; producer idempotency is
|
|
now active roadmap work.
|
|
|
|
## Active Roadmap
|
|
|
|
## Stage 1: Server-Side Upload Idempotency
|
|
|
|
Goal:
|
|
|
|
Add `Idempotency-Key` support to `POST /upload` so safe producer retries do not
|
|
create duplicate accepted runs.
|
|
|
|
Implementation scope:
|
|
|
|
- Validate optional `Idempotency-Key` headers using the syntax defined in
|
|
`docs/roadmap/producer.md`.
|
|
- Scope keys by the authenticated pipeline selected through bearer-token
|
|
mapping.
|
|
- Record accepted keys after archive staging and source bundle validation
|
|
succeed.
|
|
- Compare normalized source manifest identity, not raw archive bytes.
|
|
- Return the original accepted run response for the same pipeline, same key,
|
|
and same manifest identity.
|
|
- Return `409 Conflict` for the same pipeline and key with a different manifest
|
|
identity.
|
|
- Return a retryable conflict response when the same key is already being
|
|
processed concurrently for the same pipeline before manifest identity is
|
|
known.
|
|
- Expire idempotency records with existing upload status retention.
|
|
- Keep idempotency records memory-only; server restart clears them.
|
|
- Preserve current raw HTTP behavior when no idempotency key is supplied.
|
|
|
|
Current-behavior documentation updates after implementation:
|
|
|
|
- `docs/integrations/http-upload.md`
|
|
- `docs/operations.md`
|
|
- `docs/internal/app.md`
|
|
- `docs/troubleshooting.md`
|
|
|
|
Tests:
|
|
|
|
- Same key and same bundle returns the original run id and does not enqueue a
|
|
second run.
|
|
- Same key and different bundle returns `409`.
|
|
- Same key under different authenticated pipelines does not conflict.
|
|
- Missing key preserves current raw HTTP behavior.
|
|
- Invalid key syntax returns `400`.
|
|
- Expiration removes idempotency records.
|
|
- Tokens are never leaked; idempotency keys appear only where needed for
|
|
diagnostics.
|
|
|
|
Completion criteria:
|
|
|
|
- Existing upload clients continue to work.
|
|
- The HTTP API has an implemented, tested idempotency contract.
|
|
- Idempotent retries cannot create duplicate accepted runs.
|
|
|
|
## Stage 2: Public `pkg/upload` API And Client
|
|
|
|
Goal:
|
|
|
|
Add a producer-facing upload package that builds or validates bundles, archives
|
|
them, and submits them to the HTTP upload API.
|
|
|
|
Implementation scope:
|
|
|
|
- Add public `pkg/upload`.
|
|
- Use `pkg/bundle` for manifest generation, digest and path semantics, local
|
|
validation, and temporary bundle creation.
|
|
- Implement options-struct APIs matching `docs/roadmap/producer.md`:
|
|
`ClientOptions`, `RetryOptions`, `UploadBundleOptions`,
|
|
`UploadFilesOptions`, `Result`, `RunStatus`, `NewClient`, `UploadBundle`,
|
|
`UploadFiles`, and `Status`.
|
|
- Treat `Endpoint` as the distributor server base URL, deriving `/upload` and
|
|
`/runs/<run-id>` internally.
|
|
- Require bearer token authentication and redact token values from all errors.
|
|
- Always send `Idempotency-Key`.
|
|
- Use caller-supplied idempotency keys when provided.
|
|
- When no key is supplied, generate one random 128-bit lowercase hex key per
|
|
upload operation and reuse it across retries from that call.
|
|
- Support uploading an existing local bundle root.
|
|
- Support building a temporary bundle from explicit `bundle.BundleFile` values
|
|
and uploading it.
|
|
- Create replayable gzip-compressed tar uploads with
|
|
`Content-Type: application/gzip`.
|
|
- Retry only safe cases: `503 Service Unavailable`, temporary network errors,
|
|
and ambiguous mid-upload failures, using the same idempotency key and
|
|
replayable body.
|
|
- Do not retry `400`, `401`, `409`, `413`, or `415`.
|
|
- Do not retry after `202 Accepted`.
|
|
- Respect context cancellation before waiting and before each retry.
|
|
- Close response bodies on every attempt.
|
|
|
|
Current-behavior documentation updates after implementation:
|
|
|
|
- Update `pkg/bundle` integration references only as needed once `pkg/upload`
|
|
exists.
|
|
- Keep full user-facing docs and examples for Stage 3.
|
|
|
|
Tests:
|
|
|
|
- Client construction validates endpoint and token requirements.
|
|
- Token values are redacted from errors.
|
|
- Caller-supplied and generated idempotency keys are sent correctly.
|
|
- Existing bundle upload includes only `manifest.json` and manifest-listed
|
|
files.
|
|
- File-based upload builds a compliant temporary bundle without touching
|
|
producer source directories.
|
|
- Local validation failures prevent HTTP requests.
|
|
- Response parsing covers `202`, `400`, `401`, `409`, `413`, `415`, `503`,
|
|
non-JSON errors, and unexpected statuses.
|
|
- Retry uses the same idempotency key and stops correctly.
|
|
- Context cancellation during retry backoff is honored.
|
|
- Custom `*http.Client` behavior is covered with `httptest`.
|
|
|
|
Completion criteria:
|
|
|
|
- Go producers can upload valid bundles through `pkg/upload`.
|
|
- Safe retry behavior relies on the implemented server idempotency contract.
|
|
- Public package tests prove upload behavior does not duplicate or drift from
|
|
`pkg/bundle` semantics.
|
|
|
|
## Stage 3: Documentation And Examples
|
|
|
|
Goal:
|
|
|
|
Document implemented producer upload and idempotency behavior after the server
|
|
contract and public package exist.
|
|
|
|
Implementation scope:
|
|
|
|
- Update current-behavior docs only after Stages 1 and 2 are implemented.
|
|
- Add secret-free examples where they are safe, copyable, and describe
|
|
implemented behavior.
|
|
- Keep deferred items out of current docs.
|
|
|
|
Docs to update:
|
|
|
|
- `README.md`
|
|
- `docs/integrations/source-bundle.md`
|
|
- `docs/integrations/http-upload.md`
|
|
- `docs/operations.md`
|
|
- `docs/internal/app.md`
|
|
- `docs/policy/development.md`
|
|
- `examples/`, only if examples are safe, copyable, and implemented
|
|
|
|
Tests and checks:
|
|
|
|
```sh
|
|
go test ./...
|
|
rg -n "idempotency|Idempotency-Key|pkg/upload|UploadBundle|UploadFiles" README.md docs examples
|
|
```
|
|
|
|
Completion criteria:
|
|
|
|
- Current docs describe the implemented server idempotency and `pkg/upload`
|
|
API.
|
|
- Completed behavior is not documented only as future work.
|
|
- `docs/roadmap/` contains only future or deferred producer-upload work.
|
|
|
|
## Deferred Work
|
|
|
|
- Durable idempotency storage across server restarts.
|
|
- Database-backed queues or durable producer retry processing.
|
|
- `UploadAndWait`, long polling, run cancellation, run retry, or run listing
|
|
helpers.
|
|
- Zstandard archives.
|
|
- Multipart, resumable, or streaming upload protocols.
|
|
- URL-token authentication.
|
|
- Browser UI or public exposure defaults.
|
|
|
|
## Validation
|
|
|
|
For this documentation pass:
|
|
|
|
```sh
|
|
rg -n "Idempotency-Key|pkg/upload|UploadBundle|UploadFiles|Stage 1: Server-Side Upload Idempotency" docs/roadmap/implementation.md
|
|
rg -n "Producer-supplied idempotency keys|Producer Coordination" docs/roadmap/http.md docs/roadmap/implementation.md
|
|
rg -n "pkg/upload|UploadBundle|UploadFiles|Idempotency-Key" README.md docs examples --glob '!docs/roadmap/**'
|
|
git status --short
|
|
git diff -- docs/roadmap/implementation.md
|
|
```
|
|
|
|
Expected result:
|
|
|
|
- New future behavior appears only under `docs/roadmap/`.
|
|
- Existing unrelated worktree changes, including any current
|
|
`docs/roadmap/documentation.md` deletion, are not touched.
|
|
- This pass changes only `docs/roadmap/implementation.md`.
|