Skip to content

fix(scrape): cancel queued work and fail closed on budget - #52

Open
gildesmarais wants to merge 4 commits into
mainfrom
feat/scrape-timely-confidence
Open

fix(scrape): cancel queued work and fail closed on budget#52
gildesmarais wants to merge 4 commits into
mainfrom
feat/scrape-timely-confidence

Conversation

@gildesmarais

@gildesmarais gildesmarais commented Aug 28, 2026

Copy link
Copy Markdown
Member

What changed

  • Cancel queued scrape Futures when the client budget expires instead of waiting for a hung worker.
  • Fail closed on deadline/budget gates; cap escalate and soft-retry so one slow Chromium cannot cascade false timeouts.
  • Probe challenges mid-wait during browser readiness chunks (app/engine/browser_tier.py, detector).
  • Surface phase-honest timeout_phase strings in the error envelope / OpenAPI.
  • README ops triage table for timeout phases.
  • Specs for cancel path, budget, challenge mid-wait, and timeout HTTP mapping.

Why

One hung Chromium or false timeout was cascading: queued work kept running after the client gave up, and operators could not tell queue/boot capacity pain from a slow target site.

Risk

  • In-flight get may still finish a step after the API has already returned 504; cancel is best-effort on the queue Future.
  • Stricter fail-closed budget gates may increase timeout responses under load (intended — fail closed rather than soft-retry forever).

Review map

  1. app/domain/scrape_service.py — Future.cancel / budget fail-closed entry.
  2. app/engine/orchestrator.py + app/engine/budget.py — deadline gates and escalate/soft-retry caps.
  3. app/engine/browser_tier.py + app/infra/detector.py — mid-wait challenge probe.
  4. app/engine/envelope.py / OpenAPI — timeout_phase contract.
  5. tests/domain/test_scrape_service_cancel.py and engine challenge/budget specs — behavior locks.

Validation

  • make check exit 0

Adjacent

Rollout: merge scrape-api → release/bump gem → merge web (web uses respond_to? so pre-bump is safe).

Hold the executor Future and cancel on outer timeout so capacity waits
never start Chromium. Remaining helpers may return 0; escalate AUTO→browser
only with ≥8s left (unclean skip → challenge_block); soft retries need ≥5s
work budget; timeout error strings are phase-honest (queue/boot/work).
Chunk selector waits to ≤2s and run ChallengeDetector between chunks so
interstitials fail closed as challenge_block before burning the full wait
budget. Boyscout: call_if_available in detector, single unclean surfacing
helper, drop dead inspect params.
Map queue/boot/work and challenge_block to capacity vs product signals, and note 504 Future.cancel behavior.
Storage failures are NAVIGATION_ERROR, not timeouts; keep timeout_phase
reserved for real timeout outcomes so ops/Sentry tags stay honest.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant