Routes:
- POST /jobs: 201 on first insert, 200 on idempotent re-submit.
- GET /jobs/{id}: full Job envelope or 404.
- GET /jobs?client_id=&request_id=: correlation lookup or 404.
- GET /healthz: {postgres, ollama, ocr}; 200 iff all ok (degraded counts
as non-200 per spec). Postgres probe guarded by a 2 s wait_for.
- GET /metrics: pending/running counts + 24h done/error counters +
per-use-case avg seconds. Plain JSON, no Prometheus.
create_app(spawn_worker=bool) parameterises worker spawning so tests that
only need REST pass False. Worker spawn is tolerant of the loop module not
being importable yet (Task 3.5 fills it in).
Probes are a DI bundle — production wiring swaps them in at startup
(Chunk 4); tests inject canned ok/fail callables. Session factory is also
DI'd so tests can point at a per-loop engine and sidestep the async-pg
cross-loop future issue that bit the jobs_repo fixture.
9 new integration tests; unit suite unchanged. Forgejo Actions trigger is
flaky; local verification is the gate (unit + integration green locally).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
52 lines
1.5 KiB
Python
52 lines
1.5 KiB
Python
"""REST-adapter request / response bodies.
|
|
|
|
Most payloads reuse the core contracts directly (:class:`RequestIX`,
|
|
:class:`Job`). The only adapter-specific shape is the lightweight POST /jobs
|
|
response (`job_id`, `ix_id`, `status`) — callers don't need the full Job
|
|
envelope back on submit; they poll ``GET /jobs/{id}`` for that.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
|
|
|
|
class JobSubmitResponse(BaseModel):
|
|
"""What POST /jobs returns: just enough to poll or subscribe to callbacks."""
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
job_id: UUID
|
|
ix_id: str
|
|
status: Literal["pending", "running", "done", "error"]
|
|
|
|
|
|
class HealthStatus(BaseModel):
|
|
"""Body of GET /healthz.
|
|
|
|
Each field reports per-subsystem state. Overall HTTP status is 200 iff
|
|
every field is ``"ok"`` (spec §5). ``ollama`` can be ``"degraded"``
|
|
when the backend is reachable but the default model isn't pulled —
|
|
monitoring surfaces that as non-200.
|
|
"""
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
postgres: Literal["ok", "fail"]
|
|
ollama: Literal["ok", "degraded", "fail"]
|
|
ocr: Literal["ok", "fail"]
|
|
|
|
|
|
class MetricsResponse(BaseModel):
|
|
"""Body of GET /metrics — plain JSON (no Prometheus format for MVP)."""
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
jobs_pending: int
|
|
jobs_running: int
|
|
jobs_done_24h: int
|
|
jobs_error_24h: int
|
|
by_use_case_seconds: dict[str, float]
|