Bound ?limit and ?offset on /jobs and /dlq
This commit is contained in:
parent
761956eb70
commit
3c608046e2
3 changed files with 20 additions and 6 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
|
|
||||||
from haiku.rag.ingester.api.server import APIState, get_state
|
from haiku.rag.ingester.api.server import APIState, get_state
|
||||||
from haiku.rag.ingester.queue.models import Job, JobStatus
|
from haiku.rag.ingester.queue.models import Job, JobStatus
|
||||||
|
|
@ -9,8 +9,8 @@ router = APIRouter(prefix="/dlq", tags=["dlq"])
|
||||||
@router.get("", response_model=list[Job])
|
@router.get("", response_model=list[Job])
|
||||||
async def list_dlq(
|
async def list_dlq(
|
||||||
source_id: str | None = None,
|
source_id: str | None = None,
|
||||||
limit: int = 50,
|
limit: int = Query(50, ge=1, le=500),
|
||||||
offset: int = 0,
|
offset: int = Query(0, ge=0),
|
||||||
state: APIState = Depends(get_state),
|
state: APIState = Depends(get_state),
|
||||||
) -> list[Job]:
|
) -> list[Job]:
|
||||||
"""Jobs that exhausted retries or hit a permanent error."""
|
"""Jobs that exhausted retries or hit a permanent error."""
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
|
|
||||||
from haiku.rag.ingester.api.schemas import CancelResponse
|
from haiku.rag.ingester.api.schemas import CancelResponse
|
||||||
from haiku.rag.ingester.api.server import APIState, get_state
|
from haiku.rag.ingester.api.server import APIState, get_state
|
||||||
|
|
@ -12,8 +12,8 @@ async def list_jobs(
|
||||||
status: JobStatus | None = None,
|
status: JobStatus | None = None,
|
||||||
source_id: str | None = None,
|
source_id: str | None = None,
|
||||||
uri: str | None = None,
|
uri: str | None = None,
|
||||||
limit: int = 50,
|
limit: int = Query(50, ge=1, le=500),
|
||||||
offset: int = 0,
|
offset: int = Query(0, ge=0),
|
||||||
state: APIState = Depends(get_state),
|
state: APIState = Depends(get_state),
|
||||||
) -> list[Job]:
|
) -> list[Job]:
|
||||||
return await state.job_repo.list_jobs(
|
return await state.job_repo.list_jobs(
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,20 @@ async def test_list_jobs_returns_recent_first(state, jobs):
|
||||||
assert [j["id"] for j in payload] == [j2.id, j1.id]
|
assert [j["id"] for j in payload] == [j2.id, j1.id]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_list_jobs_rejects_out_of_range_limit_and_offset(state):
|
||||||
|
"""Limit is capped at 500 and >=1; offset is >=0. Without bounds a
|
||||||
|
malicious or careless ?limit=10000000 would block the event loop on
|
||||||
|
serialization."""
|
||||||
|
async with _client(state) as client:
|
||||||
|
for q in ("/jobs?limit=0", "/jobs?limit=501", "/jobs?offset=-1"):
|
||||||
|
resp = await client.get(q)
|
||||||
|
assert resp.status_code == 422, q
|
||||||
|
for q in ("/dlq?limit=0", "/dlq?limit=501", "/dlq?offset=-1"):
|
||||||
|
resp = await client.get(q)
|
||||||
|
assert resp.status_code == 422, q
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_list_jobs_filters_by_source_and_status(state, jobs):
|
async def test_list_jobs_filters_by_source_and_status(state, jobs):
|
||||||
# Enqueue b first so claim_next reaches it before the a row.
|
# Enqueue b first so claim_next reaches it before the a row.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue