feat(coordinator): artifact upload/download endpoints (CTX-05, part 2)

Wire the artifact storage foundation to HTTP.

- PUT /tasks/{id}/artifacts/{filename}: a worker streams a partial result;
  the coordinator verifies lease ownership (foreign worker → 409), streams
  the bytes to blob storage while hashing, and records the metadata. An
  orphaned blob from a failed metadata insert is cleaned up.
- GET /artifacts/{id}/download: streams an artifact back with its content
  type, length, and checksum.
- Ownership is read with a new non-locking TaskRepository.Get, so no row lock
  is held across a long upload. Identity travels in X-Worker-ID / X-Task-Attempt
  headers per the contract; upload/download bypass the short request timeout.
- docker-compose mounts ./data for durable artifact storage; smoke and
  requests.http exercise an upload → foreign-409 → download round-trip.
This commit is contained in:
Efremenko Arhip
2026-07-23 14:12:18 +03:00
parent dbf578c500
commit 6d45406ee0
16 changed files with 276 additions and 24 deletions
+14 -1
View File
@@ -1,6 +1,10 @@
package usecase
import "github.com/google/uuid"
import (
"io"
"github.com/google/uuid"
)
// Use-case boundary types. Adapters map their wire formats onto these, so the
// HTTP shape can change without touching business code.
@@ -46,6 +50,15 @@ type CompleteTaskInput struct {
Metrics map[string]any
}
type UploadArtifactInput struct {
TaskID uuid.UUID
WorkerID string
Attempt int
Filename string
ContentType string
Body io.Reader
}
type FailTaskInput struct {
TaskID uuid.UUID
WorkerID string