Skip to content

Latest commit

 

History

History
317 lines (264 loc) · 7.85 KB

api.md

File metadata and controls

317 lines (264 loc) · 7.85 KB

Workerfleet API

This document defines the MVP HTTP contract for the workerfleet monitoring service.

Base path: /v1

Worker ingress auth:

  • POST /v1/workers/register and POST /v1/workers/heartbeat require Authorization: Bearer <token> when WORKERFLEET_WORKER_AUTH_TOKEN is configured.
  • Missing, malformed, or invalid credentials return 401 with a generic authentication error and do not echo credential values.
  • WORKERFLEET_PROFILE=prod requires WORKERFLEET_WORKER_AUTH_TOKEN at startup, so production ingress fails closed by default.

Query API auth:

  • Query endpoints require Authorization: Bearer <token> when WORKERFLEET_ADMIN_AUTH_TOKEN is configured and query auth is required.
  • WORKERFLEET_QUERY_AUTH_REQUIRED=true requires an admin token outside production; WORKERFLEET_PROFILE=prod requires WORKERFLEET_ADMIN_AUTH_TOKEN at startup.
  • Worker ingress auth and query API auth are separate credentials. A worker token cannot list workers, tasks, alerts, or fleet summaries.
  • /healthz, /readyz, and /metrics are not covered by query API auth in this reference app.

POST /v1/workers/register

Registers or refreshes worker identity.

Request body:

{
  "worker_id": "worker-1",
  "namespace": "sim",
  "pod_name": "worker-1",
  "pod_uid": "pod-uid-1",
  "node_name": "node-a",
  "container_name": "worker",
  "image": "worker:1.0.0",
  "version": "1.0.0",
  "observed_at": "2026-04-19T10:00:00Z"
}

Success response:

{
  "data": {
    "worker_id": "worker-1",
    "status": "unknown",
    "registered_at": "2026-04-19T10:00:00Z"
  }
}

POST /v1/workers/heartbeat

Reports worker liveness, readiness, and the full active-task set.

Request body:

{
  "worker_id": "worker-1",
  "process_alive": true,
  "accepting_tasks": false,
  "observed_at": "2026-04-19T10:01:00Z",
  "last_error": "",
  "active_tasks": [
    {
      "task_id": "task-1",
      "exec_plan_id": "plan-20260419-001",
      "task_type": "simulation",
      "phase": "running",
      "phase_name": "running",
      "current_step": {
        "step": "simulate",
        "step_name": "simulation",
        "status": "running",
        "started_at": "2026-04-19T10:00:30Z",
        "updated_at": "2026-04-19T10:01:00Z",
        "attempt": 1,
        "error_class": ""
      }
    },
    {
      "task_id": "task-2",
      "exec_plan_id": "plan-20260419-001",
      "task_type": "simulation",
      "phase": "preparing",
      "phase_name": "warming",
      "current_step": {
        "step": "download_bundle",
        "step_name": "download bundle",
        "status": "running",
        "started_at": "2026-04-19T10:00:55Z",
        "updated_at": "2026-04-19T10:01:00Z",
        "attempt": 1
      }
    }
  ]
}

Notes:

  • active_tasks is a full-set replacement, not a delta stream.
  • task_id identifies one case. exec_plan_id groups cases under one simulation execution plan.
  • current_step reports the case step currently being processed. Omit it for legacy workers that cannot report step state.
  • current_step.step should come from a controlled worker-side enum such as prepare_env, download_bundle, download_data, convert_data, simulate, upload_result, or cleanup_env.
  • current_step.status should be one of running, succeeded, failed, canceled, or skipped; unknown values are normalized to unknown.
  • current_step.error_class must be low-cardinality, for example object_store_timeout or dependency_missing, not a raw exception message.
  • process_alive and accepting_tasks are distinct.
  • accepting_tasks=false with active tasks means the worker is busy, not necessarily offline.

Success response:

{
  "data": {
    "worker_id": "worker-1",
    "status": "online",
    "status_reason": "busy",
    "observed_at": "2026-04-19T10:01:00Z",
    "active_task_count": 2
  }
}

GET /v1/workers

Lists workers with optional filters.

Query parameters:

  • status
  • namespace
  • node_name
  • task_type
  • accepting_tasks
  • page
  • page_size

Success response:

{
  "data": {
    "items": [
      {
        "worker_id": "worker-1",
        "namespace": "sim",
        "pod_name": "worker-1",
        "node_name": "node-a",
        "status": "online",
        "status_reason": "busy",
        "process_alive": true,
        "accepting_tasks": false,
        "last_seen_at": "2026-04-19T10:01:00Z",
        "active_task_count": 2,
        "active_tasks": [
          {
            "task_id": "task-1",
            "exec_plan_id": "plan-20260419-001",
            "task_type": "simulation",
            "phase": "running",
            "phase_name": "running",
            "current_step": {
              "step": "simulate",
              "step_name": "simulation",
              "status": "running",
              "started_at": "2026-04-19T10:00:30Z",
              "updated_at": "2026-04-19T10:01:00Z",
              "attempt": 1
            }
          }
        ]
      }
    ],
    "page": 1,
    "page_size": 50,
    "total": 1
  }
}

GET /v1/workers/{worker_id}

Returns one worker with current active tasks and readiness state.

GET /v1/tasks/{task_id}

Returns the current or most recent task view for a task ID.

Example success payload:

{
  "data": {
    "task_id": "task-1",
    "worker_id": "worker-1",
    "exec_plan_id": "plan-20260419-001",
    "task_type": "simulation",
    "phase": "running",
    "phase_name": "running",
    "current_step": {
      "step": "simulate",
      "step_name": "simulation",
      "status": "running",
      "started_at": "2026-04-19T10:00:30Z",
      "updated_at": "2026-04-19T10:01:00Z",
      "attempt": 1
    },
    "status": "active",
    "started_at": "2026-04-19T10:00:30Z",
    "updated_at": "2026-04-19T10:01:00Z"
  }
}

Notes:

  • Query responses reuse the same read-model contract across worker detail, task detail, case timeline, and exec-plan drilldown payloads.
  • current_step is omitted from query responses when the worker does not currently report a step.

GET /v1/tasks/{task_id}/timeline

Returns case step transition and completion history for one case.

Example success payload:

{
  "data": {
    "task_id": "task-1",
    "items": [
      {
        "task_id": "task-1",
        "worker_id": "worker-1",
        "exec_plan_id": "plan-20260419-001",
        "namespace": "sim",
        "pod_name": "worker-1",
        "node_name": "node-a",
        "step": "download_bundle",
        "step_name": "download bundle",
        "status": "succeeded",
        "result": "succeeded",
        "attempt": 1,
        "started_at": "2026-04-19T10:00:10Z",
        "finished_at": "2026-04-19T10:00:30Z",
        "observed_at": "2026-04-19T10:00:30Z",
        "event_type": "task_step_finished"
      }
    ]
  }
}

GET /v1/exec-plans/{exec_plan_id}/cases

Returns paginated case step records for drilldown from Grafana aggregate panels.

Query parameters:

  • node_name
  • pod_name
  • step
  • page
  • page_size

Example success payload:

{
  "data": {
    "exec_plan_id": "plan-20260419-001",
    "items": [
      {
        "task_id": "task-1",
        "worker_id": "worker-1",
        "exec_plan_id": "plan-20260419-001",
        "pod_name": "worker-1",
        "node_name": "node-a",
        "step": "simulate",
        "status": "failed",
        "result": "failed",
        "error_class": "simulation_timeout",
        "observed_at": "2026-04-19T10:05:00Z"
      }
    ],
    "page": 1,
    "page_size": 50,
    "total": 1
  }
}

GET /v1/fleet/summary

Returns fleet totals for workers and active tasks.

GET /v1/alerts

Lists alert records.

Query parameters:

  • worker_id
  • alert_type
  • status
  • page
  • page_size

Error model

Errors use the standard contract.WriteError envelope.

  • Invalid JSON: INVALID_JSON
  • Invalid query parameter: INVALID_QUERY
  • Missing required field: REQUIRED_FIELD_MISSING
  • Resource not found: RESOURCE_NOT_FOUND