How it runs
The scheduler is started in the FastAPI lifespan hook. Every job is registered via scheduler.add_job(fn, trigger, id=..., replace_existing=True), which means the process can be restarted safely without orphaned duplicates.
scheduler = AsyncIOScheduler()
scheduler.add_job(
booking_reminders,
IntervalTrigger(hours=1),
id="booking_reminders",
replace_existing=True,
)
# ... 39 more jobs
scheduler.start()Timezone
Business-hour jobs use WITA (Central Indonesia Time, UTC+8) so that nightly and daily jobs fire at sensible Bali-local hours regardless of where the container actually runs. Pure interval jobs are timezone-agnostic.
All 39 jobs
| Job ID | Schedule | Purpose |
|---|---|---|
booking_reminders | interval · 1h | Send upcoming-booking reminders to users. |
re_engagement | cron · Mon 10:00 WITA | Weekly re-engagement nudge to lapsed users. |
venue_daily_summary | cron · 22:00 WITA daily | Evening ops summary for every venue owner. |
monthly_invoice | cron · 1st of month 09:00 WITA | Generate monthly subscription invoices. |
retry_failed_sends | interval · 60s | Retry outbound messages in the send queue. |
b2b_session_cleanup | cron · 03:00 WITA daily | Purge expired B2B onboarding sessions. |
deliver_reminders | interval · 5m | Deliver due reminders via the channel sender. |
retry_pending_fees | interval · 30m | Retry Stripe fee collections that failed. |
reap_stale_envelopes | interval · 15m | Mark PENDING envelopes past TTL as EXPIRED. |
sweep_orphaned_responses | interval · 30m | Close out venue responses with no matching booking. |
auto_confirm_stale_bookings | interval · 1h | Auto-confirm bookings venues forgot to accept. |
purge_deleted_users | cron · 04:00 WITA daily | Hard-delete users past the retention window. |
mark_completed_bookings | interval · 1h | Transition past-slot bookings to COMPLETED. |
reconcile_subscription_state | cron · 05:00 WITA daily | Reconcile local subscription rows with Stripe state. |
reconcile_fee_status | interval · 30m | Reconcile fee collection statuses against the ledger. |
recover_stuck_bookings | interval · 15m | Unstick bookings caught between A2A states. |
cancel_orphaned_bookings | interval · 30m | Cancel bookings whose envelope has been abandoned. |
retry_dispatch_failed | interval · 30m | Re-dispatch envelopes stuck in DISPATCH_FAILED. |
expire_stale_referrals | cron · 06:00 WITA daily | Expire unredeemed referral codes past their TTL. |
mark_abandoned_b2b_sessions | cron · 03:30 WITA daily | Mark half-finished B2B onboarding flows as abandoned. |
reconcile_venue_compound_state | cron · 04:00 WITA daily | Reconcile venue compound state (is_active, is_claimed, etc). |
check_price_watchers | interval · 6h | Refresh price watchers on Shopee/Tokopedia/Lazada products. |
daily_nutrition_summary | cron · 21:00 WITA daily | Send users their calorie diary summary. |
light_dreaming | cron · 02:00 WITA daily | Lightweight nightly reflection over recent interactions. |
deep_dreaming | cron · Mon 04:00 WITA | Weekly deep reflection producing new agent insights. |
dlq_cleanup | cron · 02:15 WITA daily | Trim the dead-letter queue of processed failures. |
dlq_weekly_report | cron · Mon 06:00 WITA | Weekly DLQ health report to the alerts channel. |
faq_compilation | cron · Sun 03:00 WITA | Cluster support conversations into draft FAQ entries. |
memory_eviction | cron · 03:30 WITA daily | Evict stale user memory entries past the keep window. |
reset_api_key_queries_today | cron · 08:00 WITA (00:00 UTC) | Reset the per-API-key daily query counter. |
charge_unbilled_usage | cron · 05:00 WITA daily | Batch metered ApiKeyUsageEvent rows to Stripe. |
drain_webhook_retries | interval · 2m | Retry failed outbound webhook deliveries. |
prune_error_logs | cron · 05:30 WITA daily | Delete ErrorLog rows past the retention window. |
platform_health_monitor | interval · 15m | Run platform health checks and emit alerts on regression. |
rating_prompt | interval · 1h | Prompt users to rate recent bookings. |
spend_digest | cron · 09:00 WITA daily | Send daily user-spend digest. |
rotate_delta_log | cron · Sun 04:30 WITA | Rotate the fleet delta log. |
faq_extraction | cron · Sun 23:59 WITA | Extract FAQ candidates from the week's conversations. |
rebuild_entity_graph | interval · 1h | Rebuild derived edges in the knowledge graph. |
Inspecting running jobs
The /admin/scheduler endpoint (protected by INTERNAL_API_TOKEN) returns the current job registry with next run times. Use it to verify a deploy didn't silently drop a job.
curl -H "X-Internal-Token: $INTERNAL_API_TOKEN" \
https://api.agntdot.com/admin/schedulerNightly heavy work
A few jobs under cron/ are too big to live in scheduler.py directly. They are still registered as scheduler jobs but their implementation lives in dedicated files:
cron/dreaming.py— light + deep dreaming reflectionscron/graph_builder.py— knowledge graph rebuildcron/faq_compile.py— weekly FAQ clusteringcron/wiki_reconcile.py— fleet wiki reconciliation