Scheduler
The scheduler daemon is the background process that claims and fires triggers from pgserve. It tracks worker liveness via the state management layer. It runs as a persistent loop, combining real-time PostgreSQL notifications with poll-based fallback for reliability.Architecture
Configuration
GENIE_MAX_CONCURRENT.
Trigger Lifecycle
Claiming
Triggers are claimed using PostgreSQL’sSELECT FOR UPDATE SKIP LOCKED, which provides lease-based atomic claiming across multiple scheduler instances:
Idempotency
Each trigger can carry anidempotency_key. A unique index on this column prevents double-fire:
State Flow
Cron Expressions
The cron parser supports standard 5-field expressions with extensions:- Wildcards:
* - Ranges:
1-5 - Steps:
*/10,1-5/2 - Lists:
1,3,5
Heartbeat Collection
Every 60 seconds, the scheduler collects heartbeats from all active agents:- Pane liveness — checks if tmux panes are still alive
- Agent state — reads current state from the agent registry
- Context capture — stores pane content snapshot
heartbeats table:
Machine Snapshots
Every 60 seconds (alongside heartbeats), the scheduler captures a machine-level snapshot:Orphan Reconciliation
Every 5 minutes, the scheduler scans for orphaned runs — agents that have stopped responding:- Find runs in
leasedorrunningstatus - Check if the agent has missed more than 2 consecutive heartbeats
- Mark dead runs as
failedwith a reconciliation reason - Reclaim expired leases for retry
Reboot Recovery
On startup, the scheduler performs recovery:- Reclaim expired leases — triggers where
leased_until < now()are reset topending - Reconcile orphaned runs — runs without matching live agents are marked
failed - Resume polling — normal LISTEN + poll loop begins
Structured Logging
The scheduler writes structured JSON logs to~/.genie/logs/scheduler.log: