fix(ingest): address review round 1 (reclaim queue + tests)
- Register the periodic stalled-job reclaim on a dedicated ingest-maintenance queue that every worker drains (any --tier), so reclaim still fires when the fast fleet is scaled to zero and only ocr workers run. procrastinate's periodic-defer dedup keeps it single-run across drainers. - escalation: mark `unsupported`/`forced` reason labels as reserved (not raised). - processor: note that options/progress_callback are intentionally not threaded through _parse_pdf_tier yet (symmetric with the inline path). - tests: assert TieredEscalationStrategy backoff progression (4/8/16/…/300s); cover get_ingest_pending per-queue aggregation + the legacy job_counts fallback; add an external-path zero-page no-escalation case; use the canonical INGEST_QUEUE_FAST instead of the back-compat alias. Deck #323. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9676bb3106
commit
35f8204a16
@@ -5,6 +5,8 @@ and the procrastinate TieredEscalationStrategy that turns a raised exception
|
||||
into a queue-hop / same-tier retry / give-up decision.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from procrastinate.jobs import Job
|
||||
@@ -87,6 +89,20 @@ class TestTieredEscalationStrategy:
|
||||
assert decision.queue is None
|
||||
assert decision.retry_at is not None
|
||||
|
||||
def test_transient_backoff_progression(self):
|
||||
# min(4 * 2**(attempts-1), 300): 4, 8, 16, ... capped at 300s.
|
||||
strat = self._strategy(max_transient=100)
|
||||
for attempts, expected in [(1, 4), (2, 8), (3, 16), (4, 32), (20, 300)]:
|
||||
decision = strat.get_retry_decision(
|
||||
exception=httpx.ConnectError("x"), job=_job(attempts=attempts)
|
||||
)
|
||||
assert decision is not None and decision.retry_at is not None
|
||||
delta = (decision.retry_at - datetime.now(timezone.utc)).total_seconds()
|
||||
# retry_at = now + wait; allow a small window for execution time.
|
||||
assert expected - 2 <= delta <= expected + 1, (
|
||||
f"attempts={attempts}: delta={delta:.2f}s, expected≈{expected}s"
|
||||
)
|
||||
|
||||
def test_transient_gives_up_over_cap(self):
|
||||
decision = self._strategy(max_transient=5).get_retry_decision(
|
||||
exception=httpx.ConnectError("refused"), job=_job(attempts=5)
|
||||
|
||||
Reference in New Issue
Block a user