Virke Cron
Run scheduled tasks at the edge with cron expressions. Virke cron triggers HTTP endpoints in your compute service on a schedule, with distributed locking to ensure at-most-once execution.
Requires a compute project (Virke Run).
Quick Start
1. Add a cron job
virke cron add cleanup "*/5 * * * *" /cron/cleanup
This creates a job named "cleanup" that runs every 5 minutes, calling the /cron/cleanup endpoint in your compute service.
2. Implement the handler
import { Hono } from "hono";
import { virke } from "@virke/runtime/hono";
const { fire, middleware, Bindings } = virke({ db: "my-db" });
const app = new Hono<{ Bindings: typeof Bindings }>();
app.use("*", middleware);
app.post("/cron/cleanup", async (c) => {
// Verify the request is from Virke cron
if (c.req.header("x-virke-cron") !== "true") {
return c.text("Unauthorized", 401);
}
// Your cleanup logic
const result = await c.env.db.execute(
"DELETE FROM sessions WHERE expires_at < ?",
[Date.now()]
);
return c.json({ success: true, deleted: result });
});
fire(app);
3. Deploy and verify
virke deploy
virke cron list
Cron Expression Format
Standard 5-field cron expressions:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday = 0)
│ │ │ │ │
* * * * *
Common schedules
| Expression | Description |
|---|---|
*/5 * * * * |
Every 5 minutes |
0 * * * * |
Every hour at minute 0 |
0 0 * * * |
Every day at midnight |
0 0 * * 0 |
Every Sunday at midnight |
0 9 * * 1-5 |
Every weekday at 9am |
*/15 9-17 * * 1-5 |
Every 15 min, 9am–5pm, Mon–Fri |
CLI Commands
Add a job
virke cron add <name> <schedule> <handler>
virke cron add daily-backup "0 0 * * *" /cron/backup
List jobs
virke cron list
Name Schedule Handler Enabled Last Run Next Run
daily-backup 0 0 * * * /cron/backup Yes 2026-03-04 00:00:00 2026-03-05 00:00:00
cleanup */5 * * * * /cron/cleanup Yes 2026-03-04 17:55:00 2026-03-04 18:00:00
Execution history
virke cron history <name>
Status Started At Duration (ms) Error
Success 2026-03-04 17:55:00 123.45
Success 2026-03-04 17:50:00 98.21
Error 2026-03-04 17:45:00 45.67 Timeout exceeded
Enable / disable
virke cron disable cleanup # pause without deleting
virke cron enable cleanup # resume
Remove
virke cron remove cleanup
How It Works
Virke cron uses a "cron-on-traffic" pattern:
- On every incoming request to the Virke API, the system checks if any cron jobs are due
- If a job is due, a distributed lock is acquired via KV Store
- The system makes an HTTP POST to the handler URL in your compute service
- Execution results are recorded in the control plane database
At-most-once guarantee
Distributed locks ensure each job executes at most once per schedule interval, even across multiple API instances.
Request headers
Your cron handler receives these headers:
| Header | Value |
|---|---|
x-virke-cron |
true |
x-virke-project-id |
Your project ID |
Configuration
virke.toml
[project]
name = "my-app"
[compute]
entry = "src/worker.ts"
language = "javascript"
[[cron]]
name = "cleanup"
schedule = "*/5 * * * *"
handler = "/cron/cleanup"
[[cron]]
name = "daily-report"
schedule = "0 9 * * 1-5"
handler = "/cron/report"
Best Practices
Verify cron requests
Always check the x-virke-cron header to prevent unauthorized calls:
if (c.req.header("x-virke-cron") !== "true") {
return c.text("Unauthorized", 401);
}
Keep handlers fast
Cron handlers should complete quickly. For long-running tasks, enqueue work:
app.post("/cron/process", async (c) => {
await c.env.kv.set("job_queue_process", String(Date.now()));
return c.json({ queued: true });
});
Return 2xx on success
Non-2xx responses are logged as errors in virke cron history.
Use idempotent operations
At-most-once is guaranteed but not exactly-once, so make handlers idempotent when possible:
// Idempotent — safe to run multiple times
await env.db.execute("DELETE FROM sessions WHERE expires_at < ?", [cutoff]);
// Not idempotent — increments every time
await env.db.execute("UPDATE counters SET value = value + 1");
Limitations
- Minimum interval: 1 minute
- Traffic-dependent: Jobs execute only when the API receives traffic. For guaranteed execution with zero traffic, use external health checks.
- No sub-second precision: Execution times are approximate
- Single handler per job: One HTTP endpoint per cron job
Further Reading
- Virke Run — Build the compute functions that cron triggers
- CLI Commands — Full
virke cronCLI reference - Configuration —
virke.tomlcron configuration