Cron starts the work. A durable workflow finishes it.
User schedules live as dynamic application data. A small static dispatcher finds due occurrences, deduplicates them in PostgreSQL, and enqueues resumable order-cycle jobs.
How a recurring order becomes a job
Seven steps prevent duplicates
- 01
Trigger
Graphile Worker runs
dispatch_due_schedulesevery minute. - 02
Lock
Select due schedule rows with
FOR UPDATE SKIP LOCKED. - 03
Calculate
Resolve the occurrence in the schedule’s IANA timezone, including daylight-saving behavior.
- 04
Create
Insert the order cycle with a unique constraint on schedule ID and occurrence time.
- 05
Publish
Write the job outbox in the same transaction as the new order cycle.
- 06
Advance
Calculate and store the next occurrence, respecting skip, pause, and exceptions.
- 07
Execute
Enqueue the order-cycle ID as the durable idempotency key.
Small jobs with explicit retry semantics
| Task | Purpose | Retry |
|---|---|---|
| dispatch_due_schedules | Create unique due occurrences | Safe; transaction and unique key deduplicate |
| prepare_order_cycle | Resume the order workflow | Step-aware; reconcile live cart before writes |
| send_notification | Deliver one domain-event message | Safe with event ID idempotency |
| expire_review | Expire stale snapshot and release resources | Safe if current state still awaits review |
| retailer_smoke_check | Detect selector or schema drift | Read-only and rate-limited |
A transient error before checkout may retry after reconciliation. An ambiguous response after a final action becomes checkout_unknown and requires manual verification.