154 lines
4.1 KiB
Markdown
154 lines
4.1 KiB
Markdown
# SciMesh Coordinator API Contract
|
|
|
|
**Status:** draft, version 1. This document is the compatibility boundary
|
|
between the Go coordinator and the Python Worker. Change it only in the same
|
|
pull request as both implementation and contract tests.
|
|
|
|
## General rules
|
|
|
|
- All worker endpoints require `Authorization: Bearer <token>`.
|
|
- Times use UTC RFC 3339, for example `2026-07-23T12:05:00Z`.
|
|
- JSON requests and responses use `application/json`.
|
|
- `worker_id` and `attempt` identify a lease. The coordinator validates them
|
|
transactionally on every task mutation.
|
|
- A task becomes `completed` only after a coordinator-owned artifact is durable.
|
|
- Identical repeated completion is successful; a different result for the same
|
|
attempt is a conflict.
|
|
- Coordinator API calls do not follow redirects. Artifact downloads may follow
|
|
redirects only after removing the coordinator bearer token on origin change.
|
|
|
|
## Worker registration
|
|
|
|
```http
|
|
POST /workers/register
|
|
|
|
{"name":"lab-worker-01","capabilities":["similarity-search"],"cpu_count":8,"memory_mb":16384}
|
|
```
|
|
|
|
Returns `200 OK`:
|
|
|
|
```json
|
|
{"worker_id":"uuid","heartbeat_interval_seconds":15}
|
|
```
|
|
|
|
## Task lifecycle
|
|
|
|
### Claim
|
|
|
|
```http
|
|
POST /tasks/claim
|
|
|
|
{"worker_id":"uuid","capabilities":["similarity-search"],"max_concurrency":1}
|
|
```
|
|
|
|
Returns `204 No Content` when no compatible task exists. A successful atomic
|
|
claim returns `200 OK`:
|
|
|
|
```json
|
|
{
|
|
"task_id":"uuid",
|
|
"attempt":1,
|
|
"lease_expires_at":"2026-07-23T12:05:00Z",
|
|
"workload":"similarity-search",
|
|
"input":{"uri":"https://coordinator.example/tasks/uuid/input","sha256":"hex-sha256"},
|
|
"parameters":{"query_id":"CHEMBL939","top_k":20}
|
|
}
|
|
```
|
|
|
|
The claim is one PostgreSQL transaction using `FOR UPDATE SKIP LOCKED`.
|
|
|
|
### Heartbeat
|
|
|
|
```http
|
|
POST /tasks/{task_id}/heartbeat
|
|
|
|
{"worker_id":"uuid","attempt":1}
|
|
```
|
|
|
|
Returns `200 OK` and the renewed deadline:
|
|
|
|
```json
|
|
{"lease_expires_at":"2026-07-23T12:10:00Z"}
|
|
```
|
|
|
|
The Worker schedules its next heartbeat before half of the returned TTL.
|
|
|
|
### Input download
|
|
|
|
`GET /tasks/{task_id}/input` returns the claimed task input. The Worker verifies
|
|
its SHA-256 before execution. On a redirect to another origin, it removes the
|
|
coordinator bearer token.
|
|
|
|
## Artifact upload
|
|
|
|
```http
|
|
PUT /tasks/{task_id}/artifacts/{filename}
|
|
Content-Type: text/csv
|
|
X-Worker-ID: uuid
|
|
X-Task-Attempt: 1
|
|
|
|
<streamed bytes>
|
|
```
|
|
|
|
The coordinator streams the body to storage, checks lease ownership, records
|
|
the checksum and returns `201 Created`:
|
|
|
|
```json
|
|
{
|
|
"artifact_id":"uuid",
|
|
"uri":"https://coordinator.example/artifacts/uuid/download",
|
|
"sha256":"hex-sha256",
|
|
"size_bytes":1234
|
|
}
|
|
```
|
|
|
|
The returned URI is the only URI the Worker may send in task completion.
|
|
`worker://` and `file://` are invalid.
|
|
|
|
## Completion and failure
|
|
|
|
```http
|
|
POST /tasks/{task_id}/result
|
|
|
|
{
|
|
"worker_id":"uuid",
|
|
"attempt":1,
|
|
"result":{
|
|
"artifact_id":"uuid",
|
|
"uri":"https://coordinator.example/artifacts/uuid/download",
|
|
"sha256":"hex-sha256",
|
|
"content_type":"text/csv"
|
|
},
|
|
"metrics":{"elapsed_seconds":12.4,"processed_rows":10000}
|
|
}
|
|
```
|
|
|
|
The coordinator returns `200`, `201`, or `202` for a valid completion. It must
|
|
verify that the artifact belongs to that task and attempt before completing it.
|
|
|
|
Use `POST /tasks/{task_id}/failure` only for a failed attempt:
|
|
|
|
```json
|
|
{"worker_id":"uuid","attempt":1,"error_code":"ValueError","error_message":"input checksum mismatch"}
|
|
```
|
|
|
|
Messages are sanitised: no token, traceback, absolute local path, or raw input.
|
|
|
|
## Error responses
|
|
|
|
| Situation | Response |
|
|
| --- | --- |
|
|
| Invalid JSON, field, or parameter | `400 Bad Request` |
|
|
| Missing or invalid authentication | `401 Unauthorized` / `403 Forbidden` |
|
|
| Worker/attempt does not own an active lease | `409 Conflict` |
|
|
| Artifact does not belong to the task/attempt | `409 Conflict` |
|
|
| Same attempt, different completion manifest | `409 Conflict` |
|
|
| Unexpected coordinator failure | `500` without internal details |
|
|
|
|
## Compatibility tests
|
|
|
|
Contract tests must cover: registration, `204` claim, successful claim,
|
|
heartbeat renewal, foreign worker and stale attempt conflicts, streamed upload,
|
|
checksum mismatch, success after upload, failure through `/failure`, and
|
|
idempotent completion.
|