Scheduler Architecture
The scheduler runs as a dedicated background loop withinpalyrad, initialized via spawn_scheduler_loop. It operates on a fixed-interval tick (15 seconds) to evaluate pending cron jobs, while also handling asynchronous maintenance tasks like memory vacuuming and skill re-auditing.
Key Components
| Component | Code Entity | Responsibility |
|---|---|---|
| Scheduler Loop | spawn_scheduler_loop | The main tokio loop that drives all background activities. |
| Cron Matcher | CronMatcher | Evaluates standard 5-field cron expressions against a given timestamp. |
| Job Registry | JournalStore | Persists CronJobRecord and CronRunRecord entities in SQLite. |
| Concurrency Manager | CronConcurrencyPolicy | Enforces execution constraints (Forbid, Replace, QueueOne). |
| Wake-on-Signal | tokio::sync::Notify | Allows immediate scheduler wake-up when a job is created or modified. |
Data Flow: Job Execution
The following diagram illustrates the transition from a scheduled time to an activeOrchestratorRun.
Scheduler Execution Pipeline
Sources: crates/palyra-daemon/src/cron.rs#42-100, crates/palyra-daemon/src/gateway.rs#56-71
Cron and Scheduling Logic
Palyra supports three types of scheduling defined inCronScheduleType:
- Cron: Standard
* * * * *expressions parsed byCronMatchercrates/palyra-daemon/src/cron.rs#129-156. - Every: Fixed interval execution (e.g., every 5 minutes) crates/palyra-daemon/src/cron.rs#124-124.
- At: One-time execution at a specific RFC3339 timestamp crates/palyra-daemon/src/cron.rs#125-125.
Concurrency Policies
When a job is triggered while a previous instance is still running, theCronConcurrencyPolicy determines the behavior:
Forbid: The new run is skipped and recorded asSkippedin the journal crates/palyra-daemon/src/journal.rs#133-133.Replace: The existing run is cancelled viaOrchestratorCancelRequest, and the new run starts immediately crates/palyra-daemon/src/journal.rs#134-134.QueueOne: The new run is queued; only one pending run can be queued at a time crates/palyra-daemon/src/journal.rs#135-135.
Misfire Policies
If the daemon is offline during a scheduled window,CronMisfirePolicy dictates recovery:
Skip: Ignore all missed invocations and wait for the next scheduled time crates/palyra-daemon/src/journal.rs#161-161.CatchUp: Immediately execute one run to account for the missed window crates/palyra-daemon/src/journal.rs#162-162.
Memory Maintenance and Ticks
The scheduler manages internal state health through “Ticks”—fixed intervals where specific maintenance functions are called.| Task | Interval | Function / Logic |
|---|---|---|
| Memory Maintenance | 5 minutes | Triggers MemoryMaintenanceRequest to enforce MemoryRetentionPolicy (TTL, max bytes) crates/palyra-daemon/src/cron.rs#56-56. |
| Embeddings Backfill | 10 minutes | Scans for memory items missing vector embeddings and triggers MemoryEmbeddingsBackfillOutcome crates/palyra-daemon/src/cron.rs#57-57. |
| Skill Re-Audit | 6 hours | Periodically re-verifies skill artifact signatures and security posture crates/palyra-daemon/src/cron.rs#54-54. |
Memory Retention Enforcement
TheJournalStore implements MemoryMaintenanceStatus which the scheduler invokes to:
- Purge items exceeding
ttl_dayscrates/palyra-daemon/src/journal.rs#188-188. - Vacuum the SQLite database to reclaim space.
- Enforce
max_bytesandmax_entrieslimits per session or globally crates/palyra-daemon/src/journal.rs#200-202.
Skill Re-Audit Scheduling
To ensure long-term integrity of installed plugins, the scheduler performs periodic audits. It reads theInstalledSkillsIndex and compares the current state against the SkillTrustStore.
Audit Logic Flow
- Locate
installed-index.jsonin the skills root crates/palyra-daemon/src/cron.rs#50-50. - For each skill, call
audit_skill_artifact_securitycrates/palyra-daemon/src/cron.rs#18-18. - Update
SkillStatusUpsertRequestin the journal with the new audit timestamp and trust state crates/palyra-daemon/src/cron.rs#38-38.
Implementation Details
CronMatcher Implementation
TheCronMatcher uses bit-vector style arrays to represent allowed values for minutes, hours, days, etc.
matches_components function performs a logical AND across these vectors to determine if the current DateTime satisfies the schedule crates/palyra-daemon/src/cron.rs#196-210.
Wake-on-Signal Design
To avoid waiting for the 15-secondSCHEDULER_IDLE_SLEEP when a user creates a new “Run Now” job or updates a schedule, the system uses a Notify handle.
- Signal Site:
CronServiceImplcallsnotify_waiters()after any mutation crates/palyra-daemon/src/gateway.rs#42-44. - Wait Site: The scheduler loop uses
tokio::select!between the sleep timer and the notification crates/palyra-daemon/src/cron.rs#21-21.