Scheduling & Workflows
How time-based work happens in Layers. Per-layer crons and global schedules for sync, scoring, and optimization.
Layers runs time-based work on two tiers:
- Per-layer schedules — every project layer has a cadence for its scheduled commands (defaulting to the layer template, overridable per project). Due commands fire on their own cadence.
- Global schedules — a set of platform-wide schedules that handle cross-project work (platform sync, ads metrics, optimization, scoring, reconciliation).
You don't normally interact with the scheduler directly — Layers takes care of it. But understanding the cadence is useful for debugging timing.
Per-layer cron overrides
Each layer template defines a default cron for its *-scheduled commands.
You can override per-project by setting project_layers.schedule.cron:
{
"schedule": { "cron": "37 9 * * *" }
}This is useful for:
- Timezone-specific batch windows ("run at 9:37 UTC for the EU morning").
- Smoothing load (if many projects share a default cron, override the busy ones to spread).
- Per-client SLAs (premium clients get faster cadence).
The scheduler prefers the per-layer override over the template default, so there's exactly one cron per layer at any moment. No double execution.
Global cadence
Representative global cadences you can count on:
| Domain | Cadence |
|---|---|
| Platform quick sync (counts, recent posts) | every 5 min |
| Platform full sync | every 20 min |
| Platform posts sync | every 30 min |
| Platform metadata sync | every 6h |
| Ads metrics sync (Meta / TikTok / Apple) | every 6h |
| Ads status sync (Meta / TikTok / Apple) | daily |
| Ads optimizer | daily |
| Organic performance scoring | every 4h |
| Orphan campaign detector | daily |
| Ads stuck-sync reaper | every 6h |
| RevenueCat metrics | hourly |
| Stripe metrics | hourly |
| Trending music refresh | every 12h |
| MSD reconcile | every 15 min |
| Orphaned container cleanup | every 4h |
| Webhook dispatcher tick | every 1 min |
Schedules are non-overlapping — if the previous run hasn't finished, the next trigger is skipped rather than queued.
Workflows
Every layer command runs as a durable workflow. Workflows:
- Are durable — they survive restarts.
- Are versioned — each workflow has a slug + version.
- Are idempotent at the step level — individual steps can be retried freely.
You can introspect workflow runs in the Workflow runs panel of any layer settings page.
Failure handling
When a workflow fails:
- The failure is recorded with a full trace.
- The failure is published to the notifications system.
- The workflow can be retried from the UI.
- Content-generation workflows that fail mid-flight mark their target
content_containerasfailed(so they don't appear stuck inprocessing).
See Failure modes for SLAs on each integration.