What it is
A scheduling module for SpacetimeDB applications that runs recurring jobs on either a calendar-based schedule or a fixed interval. It lives inside your server-side module, storing all schedule state directly in your database so jobs can be created, modified, or cancelled at runtime without redeployment.
Where it fits
- Periodic cleanup: A game or SaaS app needs to purge expired sessions, stale lobbies, or soft-deleted records on a regular cadence.
- Scheduled reports: A business application generates daily or weekly summaries at a specific time in a specific time zone, such as a morning digest delivered before business hours.
- Workspace archival with context: A multi-tenant app needs to archive specific workspaces with per-job arguments like retention period, not just a generic sweep.
- External sync: A module needs to call an external service on a schedule, using a stable per-invocation identifier as an idempotency key to avoid duplicate side effects.
- Self-healing automation: Any application where missed or crashed jobs need automatic detection and recovery without manual intervention.
How it works
Each job is declared statically when the module loads and bound to a single handler that runs whenever the job fires. Calendar jobs compute the next valid occurrence after each run and schedule themselves forward automatically, including handling daylight saving transitions. Fixed-interval jobs use the database's native interval mechanism and keep running without rescheduling. All schedule configuration, job health, and recent run history live in database tables, so clients can subscribe to job status in real time.
When a job fires, the module attempts to record the outcome and arm the next trigger in a single committed transaction. If the handler fails, a recovery path records the failure and reschedules the job in a separate transaction, so partial application writes are never committed alongside a failed run. A configurable failure threshold can automatically disable a job after too many consecutive failures. Because the recovery mechanism relies on a best-effort call, a process crash can occasionally leave a calendar job without a pending trigger. A periodic reconciliation sweep detects and repairs that condition on a configurable interval, and the same repair also runs automatically on any manual schedule or cancel operation.
Jobs can carry typed arguments that are stored durably alongside the schedule. When a job fires, the handler receives the argument values that were set at scheduling time, making it straightforward to run the same job logic against different targets, such as different workspaces or tenants, by scheduling multiple named jobs each with their own arguments. Argument types are part of the database schema, so changing them for an existing job requires a schema migration, while introducing a new job name provides a clean boundary for incompatible changes.

