Task Scheduler System
Cloudillo’s Task Scheduler is a sophisticated persistent task execution system that enables reliable, async background processing with dependency management, automatic retries, and cron-style scheduling. This system is critical for federation, file processing, and any operations that need to survive server restarts.
Why Task-Based Processing?
Simple async handlers cannot provide the guarantees needed for federation and file processing:
Problems with simple async:
- ✗ Lost on server restart (no persistence)
- ✗ No dependency ordering (file must finish before action)
- ✗ No automatic retry on transient failures
- ✗ No progress tracking or observability
- ✗ No priority management for resource allocation
Task scheduler solutions:
- ✅ Tasks survive server restarts (persisted via MetaAdapter)
- ✅ Dependency resolution (DAG-based ordering)
- ✅ Automatic retry with exponential backoff
- ✅ Task lifecycle tracking (pending → running → complete/failed)
- ✅ Priority-based execution via worker pool
Architecture Overview
Components
Task Trait System
All tasks implement the Task<S> trait:
Retries, dependencies, keys, and cron schedules are not trait methods — they are configured at scheduling time through the builder API (see below).
Generic State Parameter
The S parameter is the application state (typically Arc<AppState>):
Task Serialization
Tasks must serialize to strings for persistence:
Key Features
1. Dependency Tracking
Tasks can depend on other tasks forming a Directed Acyclic Graph (DAG):
Dependency Resolution:
2. Exponential Backoff Retry
Tasks can retry on failure with increasing delays. RetryPolicy::new((min, max), times) takes a min/max backoff in seconds and a retry count; the default is ((60, 3600), 10). Retries only happen when the error is retryable (Error::is_retryable()) — permanent errors fail immediately. Backoff is min * 2^attempt, capped at max.
.with_automatic_retry() is a shortcut that applies the default policy.
Backoff for min=60s:
After times retryable failures the task is marked failed and on_failed runs.
3. Cron Scheduling
Recurring tasks use cron expressions (5-field: minute hour day month weekday) or the convenience helpers daily_at(hour, minute) and weekly_at(weekday, hour, minute) (weekday 0=Sunday). After each run the scheduler computes the next execution and re-queues the task.
.run_on_startup() makes a cron task fire once immediately on startup if a scheduled run was missed while the server was down (or on first registration).
4. Persistence
Tasks are persisted to MetaAdapter and survive server restarts:
Built-in Task Types
These are the task types registered at startup (scheduler.register::<T>()):
| Task | Purpose | Location |
|---|---|---|
| ActionCreatorTask | Creates and signs action tokens for federation | cloudillo-action/src/task.rs |
| ActionVerifierTask | Validates incoming federated action tokens | cloudillo-action/src/task.rs |
| DraftPublishTask | Publishes scheduled draft actions | cloudillo-action/src/task.rs |
| ActionDeliveryTask | Delivers actions to remote instances with retry (POST to /api/inbox) |
cloudillo-action/src/delivery.rs |
| HistoryFetchTask | Fetches action history during federation sync | cloudillo-action/src/history_sync.rs |
| StatEmitTask | Emits aggregated stat actions (native hook) | cloudillo-action/src/native_hooks/stat_emit_task.rs |
| FileIdGeneratorTask | Computes content-addressed file IDs, moves files to BlobAdapter | cloudillo-file/src/descriptor.rs |
| ImageResizerTask | Generates image variants using Lanczos3 filter | cloudillo-file/src/image.rs |
| VideoTranscoderTask | Transcodes video to web formats | cloudillo-file/src/video.rs |
| AudioExtractorTask | Extracts audio metadata and previews | cloudillo-file/src/audio.rs |
| PdfProcessorTask | Extracts text, metadata, and page thumbnails from PDFs | cloudillo-file/src/pdf.rs |
| GcTask | Garbage-collects unreferenced blobs | cloudillo-file/src/gc.rs |
| EmailSenderTask | Sends emails asynchronously with retry | cloudillo-email/src/task.rs |
| CertRenewalTask / AcmeEarlyRetryTask | TLS certificate renewal via ACME | cloudillo-core/src/acme.rs |
| AuthCleanupTask | Cleans up expired auth/session data | cloudillo-auth/src/cleanup.rs |
| TenantImageUpdaterTask | Processes tenant avatar/banner images | cloudillo-profile/src/media.rs |
| ProfileRefreshBatchTask / ProfilePicSyncTask | Refreshes cached remote profile data and pictures | cloudillo-profile/src/sync.rs |
Builder Pattern API
The scheduler uses a fluent builder API for task configuration:
Key methods: key() (dedup identifier), depend_on(Vec) / depends_on(single), with_retry() / with_automatic_retry(), cron() / daily_at() / weekly_at(), schedule_after(secs) / schedule_at(ts), and the terminal methods schedule(), now(), after(secs), at(ts), after_task(id).
When a key is set, scheduling deduplicates: an existing task with the same key and identical serialized parameters is reused; if parameters changed, the stored task is updated in place. There is no per-task priority on the builder — the worker pool priority (high/medium/low) is chosen inside each task’s run() when it offloads CPU work.
Integration with Worker Pool
CPU-intensive tasks should use the worker pool:
See Also
- Worker Pool - CPU-intensive task execution
- System Architecture - Overall system design
- Actions - Action token creation/verification tasks
- File Storage - File processing tasks