# Automation Scheduler ## Purpose Describe how scheduled runs are detected, triggered, and resumed using Celery tasks and automation configs. ## Code Locations (exact paths) - Celery tasks: `backend/igny8_core/business/automation/tasks.py` - Models: `backend/igny8_core/business/automation/models.py` - Service invoked: `backend/igny8_core/business/automation/services/automation_service.py` ## High-Level Responsibilities - Periodically scan enabled automation configs to start scheduled runs. - Prevent overlapping runs per site via cache locks and active run checks. - Resume paused runs from their recorded stage. ## Detailed Behavior - `check_scheduled_automations` (Celery, hourly): - Iterates `AutomationConfig` with `is_enabled=True`. - Frequency rules: - `daily`: run when current hour matches `scheduled_time.hour`. - `weekly`: run Mondays at the scheduled hour. - `monthly`: run on the 1st of the month at the scheduled hour. - Skips if `last_run_at` is within ~23 hours or if an `AutomationRun` with `status='running'` exists for the site. - On trigger: instantiates `AutomationService(account, site)`, calls `start_automation(trigger_type='scheduled')`, updates `last_run_at` and `next_run_at` (via `_calculate_next_run`), saves config, and enqueues `run_automation_task.delay(run_id)`. - Exceptions are logged per site; lock release is handled by the service on failure paths. - `run_automation_task`: - Loads service via `from_run_id`, runs stages 1–7 sequentially. - On exception: marks run failed, records error/completed_at, and deletes site lock. - `resume_automation_task` / alias `continue_automation_task`: - Loads service via `from_run_id`, uses `current_stage` to continue remaining stages. - On exception: marks run failed, records error/completed_at. - `_calculate_next_run`: - Computes next run datetime based on frequency and `scheduled_time`, resetting seconds/microseconds; handles month rollover for monthly frequency. ## Data Structures / Models Involved (no code) - `AutomationConfig`: contains schedule fields (`frequency`, `scheduled_time`, `last_run_at`, `next_run_at`, `is_enabled`). - `AutomationRun`: records run status/stage used during resume/failure handling. ## Execution Flow 1) Celery beat (or cron) invokes `check_scheduled_automations` hourly. 2) Eligible configs spawn new runs via `AutomationService.start_automation` (includes lock + credit check). 3) `run_automation_task` executes the pipeline asynchronously. 4) Paused runs can be resumed by enqueueing `resume_automation_task`/`continue_automation_task`, which restart at `current_stage`. 5) Failures set run status to `failed` and release locks. ## Cross-Module Interactions - Uses planner/writer data inside the pipeline (see pipeline doc); billing/credits enforced at start. - Locking is done via Django cache, independent of other modules but prevents concurrent Celery runs per site. ## State Transitions - Config timestamps (`last_run_at`, `next_run_at`) update on scheduled launch. - Run status changes to `failed` on task exceptions; to `completed` at stage 7; to `paused/cancelled` via API. ## Error Handling - Scheduled start is skipped with log messages if recently run or already running. - Exceptions during run execution mark the run failed, record error message, set `completed_at`, and release the cache lock. ## Tenancy Rules - Configs and runs are site- and account-scoped; scheduler uses stored account/site from the config; no cross-tenant scheduling. ## Billing Rules - Start uses `AutomationService.start_automation`, which enforces credit sufficiency before scheduling the Celery execution. ## Background Tasks / Schedulers - Hourly `check_scheduled_automations` plus the long-running `run_automation_task` and resume tasks run in Celery workers. ## Key Design Considerations - Hourly scan with coarse matching keeps implementation simple while honoring per-site schedules. - Cache lock and active-run checks prevent double-starts from overlapping schedules or manual triggers. - Resume task reuses the same stage methods to keep behavior consistent between fresh and resumed runs. ## How Developers Should Work With This Module - When adding new frequencies, extend `check_scheduled_automations` and `_calculate_next_run` consistently. - Ensure Celery beat (or an equivalent scheduler) runs `check_scheduled_automations` hourly in production. - Preserve lock acquisition and failure handling when modifying task flows to avoid orphaned locks.