Add cron-based autonomous workflow firing with two hardening layers:
- Timezone-aware scheduling via chrono-tz: ScheduledWorkflow.timezone
(IANA identifier), compute_next_fire_at/after_tz, validate_timezone;
DST-safe, UTC fallback when absent; validated at config load and REST API
- Distributed fire-lock via SurrealDB conditional UPDATE (locked_by/locked_at
fields, 120 s TTL); WorkflowScheduler gains instance_id (UUID) as lock owner;
prevents double-fires across multi-instance deployments without extra infra
- ScheduleStore: try_acquire_fire_lock, release_fire_lock (own-instance guard),
full CRUD (load_one/all, full_upsert, patch, delete, load_runs)
- REST: 7 endpoints (GET/PUT/PATCH/DELETE schedules, runs history, manual fire)
with timezone field in all request/response types
- Migrations 010 (schedule tables) + 011 (timezone + lock columns)
- Tests: 48 passing (was 26); ADR-0034; changelog; feature docs updated
45 lines
2.5 KiB
Plaintext
45 lines
2.5 KiB
Plaintext
-- Migration 010: Scheduled Workflow Definitions and Run History
|
|
-- Enables autonomous cron-based workflow firing without REST triggers.
|
|
-- Two tables: schedule definitions (managed by TOML + DB) and an append-only run log.
|
|
|
|
DEFINE TABLE scheduled_workflows SCHEMAFULL;
|
|
|
|
DEFINE FIELD id ON TABLE scheduled_workflows TYPE record<scheduled_workflows>;
|
|
DEFINE FIELD template_name ON TABLE scheduled_workflows TYPE string ASSERT $value != NONE;
|
|
DEFINE FIELD cron_expression ON TABLE scheduled_workflows TYPE string ASSERT $value != NONE;
|
|
DEFINE FIELD initial_context ON TABLE scheduled_workflows FLEXIBLE TYPE object DEFAULT {};
|
|
DEFINE FIELD enabled ON TABLE scheduled_workflows TYPE bool DEFAULT true;
|
|
DEFINE FIELD allow_concurrent ON TABLE scheduled_workflows TYPE bool DEFAULT false;
|
|
DEFINE FIELD catch_up ON TABLE scheduled_workflows TYPE bool DEFAULT false;
|
|
DEFINE FIELD last_fired_at ON TABLE scheduled_workflows TYPE option<datetime> DEFAULT NONE;
|
|
DEFINE FIELD next_fire_at ON TABLE scheduled_workflows TYPE option<datetime> DEFAULT NONE;
|
|
DEFINE FIELD runs_count ON TABLE scheduled_workflows TYPE int DEFAULT 0;
|
|
DEFINE FIELD created_at ON TABLE scheduled_workflows TYPE datetime DEFAULT time::now();
|
|
DEFINE FIELD updated_at ON TABLE scheduled_workflows TYPE datetime DEFAULT time::now() VALUE time::now();
|
|
|
|
DEFINE INDEX idx_scheduled_workflows_template
|
|
ON TABLE scheduled_workflows COLUMNS template_name;
|
|
|
|
DEFINE INDEX idx_scheduled_workflows_enabled
|
|
ON TABLE scheduled_workflows COLUMNS enabled;
|
|
|
|
-- Append-only execution history for audit and debugging.
|
|
DEFINE TABLE schedule_runs SCHEMAFULL;
|
|
|
|
DEFINE FIELD id ON TABLE schedule_runs TYPE record<schedule_runs>;
|
|
DEFINE FIELD schedule_id ON TABLE schedule_runs TYPE string ASSERT $value != NONE;
|
|
DEFINE FIELD workflow_instance_id ON TABLE schedule_runs TYPE option<string> DEFAULT NONE;
|
|
DEFINE FIELD fired_at ON TABLE schedule_runs TYPE datetime ASSERT $value != NONE;
|
|
DEFINE FIELD status ON TABLE schedule_runs TYPE string
|
|
ASSERT $value INSIDE ['Fired', 'Skipped', 'Failed'];
|
|
DEFINE FIELD notes ON TABLE schedule_runs TYPE option<string> DEFAULT NONE;
|
|
|
|
DEFINE INDEX idx_schedule_runs_schedule_id
|
|
ON TABLE schedule_runs COLUMNS schedule_id;
|
|
|
|
DEFINE INDEX idx_schedule_runs_fired_at
|
|
ON TABLE schedule_runs COLUMNS fired_at;
|
|
|
|
DEFINE INDEX idx_schedule_runs_schedule_fired
|
|
ON TABLE schedule_runs COLUMNS schedule_id, fired_at;
|