// `nightlyReport` — a cron schedule (single-file `*.cron.tsx`). // // Runs at 02:00 UTC every day. `timezone` is MANDATORY — the cron is // interpreted in this IANA zone, never the container's local TZ. The // expression is validated at boot (a typo throws in the discovery log, // it doesn't silently never-fire). // // The handler is "a mutation the clock invokes": `ctx.app` is the same // AppContext shape a mutation gets (store + interceptors). For durable // multi-step work, prefer the `workflow: { name, payload }` form // instead of a handler. // // Zero-config coordination: on `store: 'memory'` this runs single- // process; on a multi-instance SQL store the framework advisory-lock // coordinates so exactly one replica fires each tick. import { defineSchedule } from '@voltro/runtime' import { count, eq } from '@voltro/database' import { database } from '../database/schema' export default defineSchedule({ name: 'nightlyReport', cron: '0 2 * * *', // 02:00 every day timezone: 'UTC', description: 'Logs a per-status order tally each night.', handler: async (ctx) => { // Tally placed-but-not-yet-shipped orders as a simple health signal. // // `ctx.app.store` runs as the SYSTEM subject — a schedule has no // request, so no tenant is inferred and this counts orders across // ALL tenants. For a per-tenant report, iterate tenants and add an // explicit `eq('tenantId', …)`; nothing fills it in for you. const open = await ctx.app.store.query( database.orders.where(eq('status', 'placed')).aggregate({ total: count() }).descriptor, ) const total = (open[0] as { total?: number } | undefined)?.total ?? 0 console.info(`[nightlyReport] fired for ${ctx.scheduledAt.toISOString()} — ${total} order(s) still 'placed'`) }, // optional, all default-safe: onOverlap: 'skip', maxRuntimeMs: 5 * 60_000, })