Add gracefulShutdown(), registerSignalHandlers(), and isShuttingDown()
to enable clean process termination during scraper operations.
Key changes:
- Register SIGTERM and SIGINT signal handlers for process shutdown
- Wait for in-progress scraper jobs to complete before exiting, with
a configurable timeout (SCRAPER_SHUTDOWN_TIMEOUT, default 30s)
- Release mutex lock on shutdown to prevent stale lock state
- Track shutdown state to reject new job acquisitions during shutdown
- Stop cron scheduler as part of the shutdown sequence
- Add SHUTDOWN_TIMEOUT to scraper config module
Adds 14 new tests covering shutdown lifecycle, timeout enforcement,
idempotent shutdown calls, and lock rejection during shutdown (56 total).
## Summary
Implements the top-level runScrape() orchestration function that coordinates the entire scraper pipeline end-to-end.
### What it does
- Full pipeline orchestration: Calls fetchPage, parseUnits, convertDataTypes, upsertUnits, insertPrices, markStaleUnits, updateDailySummary in sequence
- dryRun mode: When enabled, parses and validates HTML but skips all database writes
- htmlContent injection: Accepts raw HTML directly, bypassing the fetch step
- New/rented unit calculation: Diffs currently scraped units against previously active units to determine newUnitsCount and rentedUnitsCount for the daily summary
- Run history recording: Every scrape (success or failure) is recorded to the scraper_runs collection via recordScraperRun()
- Structured logging: All pipeline stages log with jobId correlation for traceability
- Error resilience: Catches and handles errors at each stage, ensuring partial failures are logged and recorded
### Test coverage (15 tests)
- Full workflow with mocked dependencies
- Result structure validation and jobId generation
- dryRun mode skips DB writes
- htmlContent bypasses fetch
- Success and failure history recording
- Fetch error handling with retry exhaustion
- Database operation error handling
- New/rented unit count calculation
- Default and scheduled trigger types
- Empty HTML (no units) edge case
Reviewed-on: #16
Co-authored-by: Stephen Minakian <stephenminakian@gmail.com>
Co-committed-by: Stephen Minakian <stephenminakian@gmail.com>
- Update all test files to use response.body.data.* instead of
response.body.* to match the API response convention
- Skip SEC-4.3 rate limiting tests (moved to Phase 5)
- All 202 tests now pass