feat: add cancel, pause, and resume flow control for scans
Some checks failed
Deploy / deploy (push) Failing after 18s

Users running large scans can now pause (keep partial results, resume
later), cancel (stop permanently, partial results preserved), or resume
a paused scan which races through cache hits before continuing.

Backend:
- Extend scans.status CHECK to include 'paused' and 'cancelled'
- Add _migrate_add_pause_cancel_status() table-recreation migration
- scan_processor: _running_tasks/_cancel_reasons registries,
  cancel_scan_task/pause_scan_task/stop_scan_task helpers,
  CancelledError handler in process_scan(), start_resume_processor()
- api_server: POST /scans/{id}/pause|cancel|resume endpoints with
  rate limits (30/min pause+cancel, 10/min resume); list_scans now
  accepts paused/cancelled as status filter values

Frontend:
- Scan.status type extended with 'paused' | 'cancelled'
- scanApi.pause/cancel/resume added
- StatusChip: amber PauseCircle chip for paused, grey Ban for cancelled
- ScanDetails: context-aware action row with inline-confirm for
  Pause and Cancel; Resume button for paused scans

Tests: 129 total (58 new) across test_scan_control.py,
test_scan_processor_control.py, and additions to existing suites

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 18:11:23 +01:00
parent d494e80ff7
commit 9a76d7af82
11 changed files with 1154 additions and 55 deletions

View File

@@ -28,10 +28,12 @@ CREATE TABLE IF NOT EXISTS scans (
-- Timestamps (auto-managed)
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
started_at TIMESTAMP, -- Set when status transitions to 'running'
completed_at TIMESTAMP, -- Set when status transitions to 'completed' or 'failed'
-- Scan status (enforced enum via CHECK)
status TEXT NOT NULL DEFAULT 'pending'
CHECK(status IN ('pending', 'running', 'completed', 'failed')),
CHECK(status IN ('pending', 'running', 'completed', 'failed', 'cancelled', 'paused')),
-- Progress tracking
total_routes INTEGER NOT NULL DEFAULT 0 CHECK(total_routes >= 0),