feat: add cancel, pause, and resume flow control for scans
Some checks failed
Deploy / deploy (push) Failing after 18s
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:
@@ -86,6 +86,25 @@ class TestScanWorkflow:
|
||||
prices = [r["min_price"] for r in routes]
|
||||
assert prices == sorted(prices)
|
||||
|
||||
def test_pause_and_resume_preserves_scan_id(self, client: TestClient, create_test_scan):
|
||||
"""Resume returns the same scan id, not a new one (unlike Re-run)."""
|
||||
scan_id = create_test_scan(status='running')
|
||||
|
||||
# Pause
|
||||
pause_resp = client.post(f"/api/v1/scans/{scan_id}/pause")
|
||||
assert pause_resp.status_code == 200
|
||||
assert pause_resp.json()["id"] == scan_id
|
||||
|
||||
# Resume
|
||||
resume_resp = client.post(f"/api/v1/scans/{scan_id}/resume")
|
||||
assert resume_resp.status_code == 200
|
||||
assert resume_resp.json()["id"] == scan_id
|
||||
|
||||
# Confirm scan still exists with same id
|
||||
get_resp = client.get(f"/api/v1/scans/{scan_id}")
|
||||
assert get_resp.status_code == 200
|
||||
assert get_resp.json()["id"] == scan_id
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.database
|
||||
|
||||
Reference in New Issue
Block a user