Scanner Job Dispatch
Scanner job dispatch is the pull-based protocol that transfers scan assignments from the dispatcher to each scanner. Scanners poll for pending jobs, claim them, report progress, and submit completion — the ingest nodes coordinate this lifecycle. Understanding the job protocol is essential when debugging stalled scans, investigating scanner connectivity issues, or integrating a custom scanner implementation.
Fields & Columns
| Name | Description |
|---|---|
| jobId | Unique integer identifying a scan job. Stable across the job lifecycle. |
| scanId | The parent scan this job belongs to. Multiple jobs may share the same scanId when a scan spans multiple scanners. |
| targets | Array of IP ranges and port combinations assigned to this job. |
| maxProbesPerSecond | Effective rate limit for this job, computed from the scanner, subnet, and port list rate limits using slowest-wins logic. |
| progressCount | Number of hosts probed so far (sent in progress updates). |
| resultCount | Number of results recorded so far (sent in progress updates and completion). |
| status | Final job outcome: "completed" (scanner finished successfully) or "failed" (scanner reported an error). |
| errorMessage | Optional human-readable error description sent with a "failed" completion. |
How To
Understand the job lifecycle
- Dispatcher creates pending jobs in the jobs database for each scanner assigned to a scan.
- Scanner calls GET /scanner/jobs to claim and receive pending assignments. Uses FOR UPDATE SKIP LOCKED for concurrent-safe claiming across multiple ingest nodes.
- Scanner calls POST /scanner/jobs/:jobId/start to mark the job as running.
- Scanner calls POST /scanner/jobs/:jobId/progress periodically with progressCount and resultCount as it scans.
- Scanner calls POST /scanner/jobs/:jobId/complete with status "completed" or "failed" and a final resultCount.
- When all jobs for a scan finish, the ingest node marks the parent scan as completed or failed.
Debug a stalled scan
- Check the scan status via GET /api/scans/:id — if it shows "running" for an extended period, jobs may be stuck.
- Check scanner heartbeat status in Config > Scanners to confirm the scanner is online.
- Verify the scanner process is running and can reach the ingest endpoint (port 443).
- A scan marked stuck will trigger the scan-stuck alarm after all jobs are finished but the scan remains in "running" state.
Gotchas
- Job ownership is enforced: a scanner can only start, update, or complete jobs assigned to it. Attempting to modify another scanner's job returns 403.
- Scanners authenticate using the X-API-Key header (not session cookies). A missing or invalid key returns 401.
- IP binding is checked on job fetches (GET /scanner/jobs). A scanner connecting from an unexpected IP will receive 403 with code IP_BINDING_VIOLATION.
- The limit query parameter on GET /scanner/jobs defaults to 1 and caps at 10. Scanners should claim one job at a time unless they are designed to parallelize.
- If a scanner disappears mid-job (heartbeat timeout), the job remains in "running" state. The dispatcher may re-assign it after a configurable timeout.
- All job endpoints require a valid API key. Disabled scanners receive 403 on all job operations.
API Calls (4)
| Method | Path | Description |
|---|---|---|
| GET | /scanner/jobs | Claim and receive pending jobs for this scanner. Uses X-API-Key header. Optional ?limit=1 parameter (max 10). Returns { jobs: [...] }. |
| POST | /scanner/jobs/:jobId/start | Transition a claimed job to running state. Called immediately after the scanner begins work. Returns { ok: true }. |
| POST | /scanner/jobs/:jobId/progress | Stream incremental progress. Body: { progressCount, resultCount }. Call periodically during scanning. Returns { ok: true }. |
| POST | /scanner/jobs/:jobId/complete | Finalize a job. Body: { status: "completed"|"failed", resultCount?, errorMessage? }. Triggers scan completion check when all jobs finish. |
Related Pages
- Scanner Heartbeat — Heartbeat and job protocol are the two core scanner-to-ingest communication channels
- Scanners — Scanner provisioning and configuration governs which jobs each scanner receives
- Scan Status — Scan status reflects the aggregate outcome of all its component jobs