Cron-based test run scheduler (ENH-006).
Manages one node-cron task per project schedule. Tasks are stored in a
process-local Map keyed by projectId. On startup the server calls
initScheduler which loads every enabled schedule from the DB and
arms each cron task. When a project's schedule is created, updated, or
toggled, the caller invokes reloadSchedule to apply the change
without a process restart.
Firing logic
When a cron task fires it behaves identically to POST /api/projects/:id/run:
- Loads the project and its approved tests from the DB.
- Skips if an active run is already in progress (prevents double-runs).
- Creates a
test_runrun record and hands off torunWithAbort. - Records
lastRunAt/nextRunAtviascheduleRepo.updateRunTimes(). - Logs a
scheduled_run.startactivity entry.
Exports
initScheduler— Load all enabled schedules at startup.reloadSchedule— Upsert a single project's task (create/update/toggle).stopSchedule— Cancel and remove a task (project deleted).getNextRunAt— Compute the ISO next-fire time for a cron expression.
- Source:
Members
(inner) _staleDetectionTask :Object|null
Weekly stale test detection task (AUTO-013).
Type:
- Object | null
- Source:
(inner, constant) _tzFormatters
Extract date/time components from a UTC timestamp in a given IANA timezone.
Uses Intl.DateTimeFormat.formatToParts() — the spec-guaranteed approach
for timezone-aware field extraction. Unlike the toLocaleString round-trip
(new Date(d.toLocaleString("en-US", { timeZone }))), this does not
depend on locale-specific date string formatting or parsing, and handles
DST transitions correctly (spring-forward gaps, fall-back overlaps).
- Source:
(inner, constant) tasks :Map.<string, Object>
projectId → node-cron ScheduledTask
Type:
- Map.<string, Object>
- Source:
Methods
(static) activeTaskCount() → {number}
Return the number of currently active (armed) cron tasks. Exposed for the /api/system health endpoint.
- Source:
Returns:
- Type
- number
(static) getNextRunAt(cronExpr, timezoneopt) → {string|null}
Compute the next fire time for a cron expression in a given timezone. Returns an ISO 8601 string or null if the expression is invalid.
We use a lightweight approach: advance minute-by-minute from now (max 1 year) until the cron fields match. For common schedules this resolves in at most 525,960 steps, typically far fewer. A real cron-parser library would be cleaner but avoids a new dependency.
Timezone conversion uses Intl.DateTimeFormat.formatToParts() — the
spec-guaranteed approach that correctly handles DST transitions.
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
cronExpr |
string | 5-field cron expression. |
|
timezone |
string |
<optional> |
IANA timezone (defaults to "UTC"). |
- Source:
Returns:
- Type
- string | null
(static) initScheduler()
Load all enabled schedules from the database and arm cron tasks.
Also starts the weekly stale test detection job (AUTO-013).
Called once from index.js after DB init.
- Source:
(static) reloadSchedule(projectId)
Reload a single project's cron task after a schedule create/update/toggle. Fetches the latest schedule from the DB and re-arms the task.
Parameters:
| Name | Type | Description |
|---|---|---|
projectId |
string |
- Source:
(static) stopAllTasks()
Stop and remove all active cron tasks. Called during graceful shutdown so no new scheduled runs fire while in-flight work is draining.
- Source:
(static) stopSchedule(projectId)
Stop and remove the task for a project. Called when a project is deleted so the cron task doesn't fire against a non-existent project.
Parameters:
| Name | Type | Description |
|---|---|---|
projectId |
string |
- Source:
(inner) armTask(schedule)
Arm (or re-arm) a cron task for a project schedule. If the schedule is disabled or has an invalid cron expression, the task is cancelled and removed.
Parameters:
| Name | Type | Description |
|---|---|---|
schedule |
Object | Schedule row from scheduleRepo |
- Source:
(inner) cancelTask(projectId)
Cancel and remove an existing task for a project (if any).
Parameters:
| Name | Type | Description |
|---|---|---|
projectId |
string |
- Source:
(async, inner) fireScheduledRun(projectId)
Execute a test run for a project as triggered by a cron schedule.
Mirrors the logic in POST /api/projects/:id/run.
Parameters:
| Name | Type | Description |
|---|---|---|
projectId |
string |
- Source: