## Demo: cron ### Cron.svelte ```svelte ``` ### CronLog.svelte ```svelte
{status}
``` ### cron.server.ts ```ts import { Mochi } from 'mochi-framework'; import type { CronLogEntry } from './types'; const MAX_ENTRIES = 100; // The cron appends one entry per minute forever; trimming to the last MAX_ENTRIES keeps the in-memory log bounded. const log: CronLogEntry[] = []; let seq = 0; type WsClient = { send: (data: string) => void }; const clients = new Set(); function broadcast(message: string): void { for (const ws of clients) { ws.send(message); } } // The site rides the default `cronStorage: 'memory'`, so the demo writes no file into the working dir; set // `Mochi.serve({ cronStorage })` to make the schedule durable across restarts and multiple nodes. export const activityLog = Mochi.cron('demo-activity-log', '* * * * *', (run) => { const entry: CronLogEntry = { seq: ++seq, at: Date.now(), scheduledTime: run.scheduledTime }; log.push(entry); if (log.length > MAX_ENTRIES) { log.splice(0, log.length - MAX_ENTRIES); } broadcast(JSON.stringify({ type: 'entry', entry })); }); export function addClient(ws: WsClient): void { clients.add(ws); ws.send(JSON.stringify({ type: 'snapshot', entries: [...log].reverse() })); } export function removeClient(ws: WsClient): void { clients.delete(ws); } ``` ### types.ts ```ts // Components must import types from here, NOT from cron.server.ts: a type import from a side-effectful server // module still drags that module into the SSR component bundle, re-registering its cron job a second time. export interface CronLogEntry { seq: number; /** Epoch ms at which the cron handler ran. */ at: number; /** Epoch ms at which the scheduler claimed the firing, which is earlier than `at` by the queue pickup delay. */ scheduledTime: number; } export type CronLogMessage = { type: 'snapshot'; entries: CronLogEntry[] } | { type: 'entry'; entry: CronLogEntry }; ``` ### routes.ts ```ts import { Mochi } from 'mochi-framework'; import type { MochiRouteValue, MochiCronConfig } from 'mochi-framework'; import { activityLog, addClient, removeClient } from './cron.server'; // Mounted in the site's Mochi.serve({ cron }) call — see src/routes.ts. export const cron: MochiCronConfig[] = [activityLog]; export const routes: Record = { '/demos/cron': Mochi.page('./src/demos/cron/Cron.svelte'), '/ws/cron-log': Mochi.ws({ open(ws) { addClient(ws); }, message() {}, close(ws) { removeClient(ws); }, }), }; ``` ### index.ts ```ts import { Mochi, logger } from 'mochi-framework'; import { routes, cron } from './routes'; await Mochi.serve({ port: 3333, development: process.env.MODE === 'development', routes, cron, }); logger.info('Server running at http://localhost:3333'); ```