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:
@@ -80,6 +80,24 @@ Content-Type: application/json
|
||||
"attempt": {{attempt}}
|
||||
}
|
||||
|
||||
### 3a. Upload a partial-result artifact (200) — while the task is leased
|
||||
# Identity travels in headers per the contract; the body is streamed as-is.
|
||||
# @name uploadArtifact
|
||||
PUT {{host}}/tasks/{{taskId}}/artifacts/result.csv
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: text/csv
|
||||
X-Worker-ID: {{worker}}
|
||||
X-Task-Attempt: {{attempt}}
|
||||
|
||||
query,match,score
|
||||
CHEMBL25,CHEMBL139,0.87
|
||||
|
||||
@artifactId = {{uploadArtifact.response.body.artifact_id}}
|
||||
|
||||
### 3b. Download the artifact by id (200)
|
||||
GET {{host}}/artifacts/{{artifactId}}/download
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
### 4. Submit the result (200)
|
||||
POST {{host}}/tasks/{{taskId}}/result
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
Reference in New Issue
Block a user