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

  1. Dispatcher creates pending jobs in the jobs database for each scanner assigned to a scan.
  2. Scanner calls GET /scanner/jobs to claim and receive pending assignments. Uses FOR UPDATE SKIP LOCKED for concurrent-safe claiming across multiple ingest nodes.
  3. Scanner calls POST /scanner/jobs/:jobId/start to mark the job as running.
  4. Scanner calls POST /scanner/jobs/:jobId/progress periodically with progressCount and resultCount as it scans.
  5. Scanner calls POST /scanner/jobs/:jobId/complete with status "completed" or "failed" and a final resultCount.
  6. When all jobs for a scan finish, the ingest node marks the parent scan as completed or failed.

Debug a stalled scan

  1. Check the scan status via GET /api/scans/:id — if it shows "running" for an extended period, jobs may be stuck.
  2. Check scanner heartbeat status in Config > Scanners to confirm the scanner is online.
  3. Verify the scanner process is running and can reach the ingest endpoint (port 443).
  4. A scan marked stuck will trigger the scan-stuck alarm after all jobs are finished but the scan remains in "running" state.

Gotchas

  1. 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.
  2. Scanners authenticate using the X-API-Key header (not session cookies). A missing or invalid key returns 401.
  3. 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.
  4. 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.
  5. If a scanner disappears mid-job (heartbeat timeout), the job remains in "running" state. The dispatcher may re-assign it after a configurable timeout.
  6. 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