Skip to main content
The Palyra scheduler is a central background orchestration system responsible for executing recurring jobs, maintaining system health via periodic ticks, and managing the lifecycle of background tasks with complex concurrency and misfire policies.

Scheduler Architecture

The scheduler runs as a dedicated background loop within palyrad, 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

ComponentCode EntityResponsibility
Scheduler Loopspawn_scheduler_loopThe main tokio loop that drives all background activities.
Cron MatcherCronMatcherEvaluates standard 5-field cron expressions against a given timestamp.
Job RegistryJournalStorePersists CronJobRecord and CronRunRecord entities in SQLite.
Concurrency ManagerCronConcurrencyPolicyEnforces execution constraints (Forbid, Replace, QueueOne).
Wake-on-Signaltokio::sync::NotifyAllows 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 active OrchestratorRun. 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 in CronScheduleType:
  1. Cron: Standard * * * * * expressions parsed by CronMatcher crates/palyra-daemon/src/cron.rs#129-156.
  2. Every: Fixed interval execution (e.g., every 5 minutes) crates/palyra-daemon/src/cron.rs#124-124.
  3. 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, the CronConcurrencyPolicy determines the behavior:

Misfire Policies

If the daemon is offline during a scheduled window, CronMisfirePolicy dictates recovery: Sources: crates/palyra-daemon/src/journal.rs#130-163, crates/palyra-daemon/src/cron.rs#122-174

Memory Maintenance and Ticks

The scheduler manages internal state health through “Ticks”—fixed intervals where specific maintenance functions are called.
TaskIntervalFunction / Logic
Memory Maintenance5 minutesTriggers MemoryMaintenanceRequest to enforce MemoryRetentionPolicy (TTL, max bytes) crates/palyra-daemon/src/cron.rs#56-56.
Embeddings Backfill10 minutesScans for memory items missing vector embeddings and triggers MemoryEmbeddingsBackfillOutcome crates/palyra-daemon/src/cron.rs#57-57.
Skill Re-Audit6 hoursPeriodically re-verifies skill artifact signatures and security posture crates/palyra-daemon/src/cron.rs#54-54.

Memory Retention Enforcement

The JournalStore implements MemoryMaintenanceStatus which the scheduler invokes to:
  1. Purge items exceeding ttl_days crates/palyra-daemon/src/journal.rs#188-188.
  2. Vacuum the SQLite database to reclaim space.
  3. Enforce max_bytes and max_entries limits per session or globally crates/palyra-daemon/src/journal.rs#200-202.
Sources: crates/palyra-daemon/src/cron.rs#50-58, crates/palyra-daemon/src/journal.rs#63-66

Skill Re-Audit Scheduling

To ensure long-term integrity of installed plugins, the scheduler performs periodic audits. It reads the InstalledSkillsIndex and compares the current state against the SkillTrustStore. Audit Logic Flow
  1. Locate installed-index.json in the skills root crates/palyra-daemon/src/cron.rs#50-50.
  2. For each skill, call audit_skill_artifact_security crates/palyra-daemon/src/cron.rs#18-18.
  3. Update SkillStatusUpsertRequest in the journal with the new audit timestamp and trust state crates/palyra-daemon/src/cron.rs#38-38.
Sources: crates/palyra-daemon/src/cron.rs#100-120, crates/palyra-daemon/src/journal.rs#70-70

Implementation Details

CronMatcher Implementation

The CronMatcher uses bit-vector style arrays to represent allowed values for minutes, hours, days, etc.
struct CronMatcher {
    minutes: Vec<bool>,       // 0-59
    hours: Vec<bool>,         // 0-23
    day_of_month: Vec<bool>,  // 1-31
    months: Vec<bool>,        // 1-12
    weekdays: Vec<bool>,      // 0-6
    day_of_month_wildcard: bool,
    weekdays_wildcard: bool,
}
The 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-second SCHEDULER_IDLE_SLEEP when a user creates a new “Run Now” job or updates a schedule, the system uses a Notify handle. Sources: crates/palyra-daemon/src/cron.rs#129-156, crates/palyra-daemon/src/cron.rs#42-42