Skip to content

Add cron action executor (scheduled trigger)#9

Merged
jaredzwick merged 1 commit intomainfrom
cron-executor
May 3, 2026
Merged

Add cron action executor (scheduled trigger)#9
jaredzwick merged 1 commit intomainfrom
cron-executor

Conversation

@jaredzwick
Copy link
Copy Markdown
Collaborator

Summary

  • Second action executor for pypesdev/agents. A cron action wraps another Action with a 5-, 6-, or 7-field cron expression and fires it on schedule via an in-process scheduler. Mirrors the typed-spec pattern of the webhook executor shipped in Add webhook action executor (HTTP POST) #8.
  • src/executors/cron.rs exposes a pure parse / next_fire_after API plus a Scheduler with a tick(now) shape so unit tests drive it with a mock clock and the real loop drives it with Utc::now().
  • process_actions reports the next computed fire time for cron entries (ExecutionOutcome::Cron(...)); actual firing is handled by Scheduler. Out of scope for v1: distributed scheduling and persistent missed-fire catchup.

Example output

```
$ cargo run --example cron_executor
→ stored action: {"type":"cron","expression":"* * * * * *","action":{"type":"webhook","url":"http://127.0.0.1:51657/hook\",\"headers\":{},\"payload\":{\"event\":\"cron.tick\",\"n\":1}}}
⏲ next fire scheduled at 2026-05-03 09:11:52 UTC (in 943 ms)
← cron[0] fired webhook → status=200 body={"ok":true}
✓ mock receiver got 1 request(s):
{"event":"cron.tick","n":1}
```

Test plan

  • cargo test — 18 passed (10 new, 8 pre-existing)
  • cargo run --example cron_executor — terminates in <1s, fires the wrapped webhook, mock receiver captures the payload
  • Mock-clock unit test (scheduler_fires_on_time_with_mock_clock) drives due_at / advance deterministically
  • Real-time integration test (scheduler_next_due_waits_for_real_tick) confirms next_due blocks until the scheduled instant
  • Round-trip serde test for the recursive Action::Cron { action: Box<Action> } shape

Closes HIR-118.

Wraps another action with a 5-, 6-, or 7-field cron expression and fires
it on schedule via an in-process scheduler. Mirrors the typed-spec pattern
of the webhook executor (HIR-110).

- src/executors/cron.rs with parse / next_fire_after / Scheduler
- Action::Cron(CronAction) variant; ExecutionOutcome::Cron(...)
- examples/cron_executor.rs — fires once on the next per-second tick
- README + CHANGELOG sections

Closes HIR-118.
@jaredzwick
Copy link
Copy Markdown
Collaborator Author

CTO review — approved, merging

Verified:

  • 18/18 tests green; new tests cover 5/6/7-field parse, strictly-after semantics, mock-clock fire-on-time, real-clock integration, and Action::Cron serde round-trip.
  • Pure parse / next_fire_after split from stateful Scheduler — testable and cleanly composable.
  • process_actions correctly reports next fire without firing inline; firing routes through Scheduler.
  • Example terminates in ~1s as specified; README + CHANGELOG updated.
  • Out-of-scope items (distributed scheduling, restart catchup, LLM executor) match the ticket.

Follow-up (separate ticket I'll file): wire Scheduler into a long-running daemon runtime so cron actions actually fire in production. Daemon today only handles process plumbing — needs an agent execution loop. Not blocking this merge.

@jaredzwick jaredzwick merged commit 715258e into main May 3, 2026
1 check passed
@jaredzwick jaredzwick deleted the cron-executor branch May 3, 2026 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant