Cron Jobs

Schedule tasks with cronJobs() — interval, daily, weekly, cron

Gencow provides a built-in scheduler for cron jobs. Define scheduled tasks in gencow/crons.ts and they run automatically.

Setup

Create gencow/crons.ts (auto-generated by gencow init):

import { cronJobs } from "@gencow/core";

const crons = cronJobs();

// Define your scheduled jobs here

export default crons;  // ← Required!

Critical: You must export default crons — without it, the scheduler won't register your jobs.

Scheduling Methods

interval — Run Every N Minutes/Hours

crons.interval("syncData", { minutes: 30 }, "data.sync");
// Runs data.sync mutation every 30 minutes

Options: { minutes?: number, hours?: number, seconds?: number }

daily — Run Once Per Day

crons.daily("morningReport", { hour: 9, minute: 0 }, "reports.daily");
// Runs reports.daily mutation every day at 09:00

Options: { hour: number, minute?: number }

weekly — Run Once Per Week

crons.weekly("weeklyDigest", { dayOfWeek: 1, hour: 10 }, "reports.weekly");
// Runs reports.weekly mutation every Monday at 10:00

Options: { dayOfWeek: number (0=Sun, 1=Mon, ..., 6=Sat), hour: number, minute?: number }

cron — Standard Cron Expression

crons.cron("customSchedule", "*/15 * * * *", "tasks.cleanup");
// Standard cron: every 15 minutes

Inline Handlers

Cloud deployments register only string action cron jobs in the platform scheduler. Inline async handlers can run in local app runtime paths, but they are skipped from the cloud cron manifest because functions cannot be safely serialized into the platform control plane.

Instead of referencing a mutation by name, you can pass an inline async function:

crons.interval("healthCheck", { minutes: 5 }, async (ctx) => {
    const result = await fetch(`${process.env.GENCOW_INTERNAL_URL}/health`);
    if (!result.ok) {
        console.error("Health check failed!");
    }
});

Complete Example

// gencow/crons.ts
import { cronJobs } from "@gencow/core";

const crons = cronJobs();

// Every 30 minutes: sync external data
crons.interval("syncNews", { minutes: 30 }, "news.sync");

// Every day at 9:00 AM: generate daily report
crons.daily("dailyReport", { hour: 9 }, "reports.generateDaily");

// Every Monday at 10:00 AM: weekly summary
crons.weekly("weeklySummary", { dayOfWeek: 1, hour: 10 }, "reports.generateWeekly");

// Every 15 minutes: cleanup expired sessions
crons.cron("cleanup", "*/15 * * * *", "admin.cleanup");

export default crons;

The Mutation Handler

// gencow/news.ts
import { procedure } from "./runtime";
import { news } from "./schema";

export const sync = procedure.mutation
    .name("news.sync")
    .handler(async ({ context: ctx }) => {
        const response = await fetch("https://api.example.com/news");
        const articles = await response.json();

        for (const article of articles) {
            await ctx.db.insert(news).values({
                title: article.title,
                url: article.url,
                fetchedAt: new Date(),
            }).onConflictDoNothing();
        }

        console.log(`Synced ${articles.length} articles`);
    });

Self-Fetch Pattern

When a cron job needs to call its own server's API:

crons.interval("healthPing", { minutes: 5 }, async (ctx) => {
    // Use GENCOW_INTERNAL_URL (auto-injected at server boot)
    const url = process.env.GENCOW_INTERNAL_URL;
    const res = await fetch(`${url}/api/health`);
    console.log("Health:", res.status);
});

Note: GENCOW_INTERNAL_URL is automatically set by the server in both cloud and local modes. Don't hardcode URLs or ports.

Register in index.ts

Make sure your cron module's mutations are exported in gencow/index.ts:

export * as tasks from "./tasks";
export * as news from "./news";       // ← cron handler mutations
export * as reports from "./reports"; // ← cron handler mutations

Viewing Cron Status

  • Dashboard: Admin Dashboard → Scheduler tab
  • Logs: Cron execution results appear in gencow dev console output

Cloud Deployment

When you run gencow deploy or cloud dev packaging, the CLI reads gencow/crons.ts and writes a dependency-free .gencow/cron-jobs.json into the deploy bundle. The platform syncs cron_jobs from this manifest instead of importing your TypeScript file in the control-plane process.

This matters because cloud deployment can prune platform packages such as @gencow/core from the app node_modules. Your source should still import cronJobs from @gencow/core; the manifest is the deployment artifact that makes platform cron sync stable.

Important Notes

  1. export default crons is required — without it, no jobs are registered
  2. Cloud cron handlers must use string mutation action names, not queries; inline async functions are local-runtime only
  3. Mutation string names (e.g., "news.sync") must match exactly: {module}.{export}
  4. All times are in server timezone (UTC in cloud deployments)
  5. Cron jobs run even when no users are connected

Next Steps