Monitor Deno cron jobs: Deno.cron native API and built-in fetch, zero dependencies
Deno.cron is a first-party cron API, stable in Deno 2.x.
Wrap the handler in try/catch: await fetch(PING) on
success; await fetch(PING + '/fail', ...) with the error
body on failure; re-throw so Deno marks the run as failed. Built-in
fetch, no npm, no dependencies. Absence detection covers
the process that never starts or is killed. Free, no monitor cap.
Your assistant can do this for you
Monitor my Deno scripts with LastPing
On this page
The snippets
Create a monitor in the console, set the schedule plus a grace window, copy the ping URL, and add it to your script.
Deno.cron: basic try/catch (Deno 2.x)
Deno.cron accepts a name, a cron expression, and an
async handler. Re-throw after the /fail ping so Deno
can apply its own failure handling:
// job.ts — Deno 2.x (Deno.cron is stable, no flags needed)
const PING = Deno.env.get("LASTPING_URL")
?? "https://ping.lastping.dev/<your-monitor-id>";
async function runJob(): Promise<void> {
// your job
}
Deno.cron("nightly-etl", "0 2 * * *", async () => {
try {
await runJob();
await fetch(PING);
} catch (err) {
const msg = String(err instanceof Error ? err.stack : err);
await fetch(`${PING}/fail`, {
method: "POST",
body: msg.slice(0, 10_000),
headers: { "Content-Type": "text/plain" },
});
throw err; // re-throw so Deno marks the run as failed
}
});
With /start ping for overrun detection
A /start ping arms the hung-job alarm. A
rid pairs start with finish so each run's duration
is recorded in the event trail:
Deno.cron("nightly-etl", "0 2 * * *", async () => {
const rid = Date.now().toString();
await fetch(`${PING}/start?rid=${rid}`);
try {
await runJob();
await fetch(`${PING}?rid=${rid}`);
} catch (err) {
const msg = String(err instanceof Error ? err.stack : err);
await fetch(`${PING}/fail`, {
method: "POST",
body: msg.slice(0, 10_000),
});
throw err;
}
});
Deno 1.x: with --unstable-cron flag
On Deno 1.38–1.x, pass --unstable-cron at startup.
The API is identical; only the startup flag differs:
# deno run --unstable-cron --allow-net --allow-env job.ts
// job.ts (same API as Deno 2.x)
const PING = Deno.env.get("LASTPING_URL")
?? "https://ping.lastping.dev/<your-monitor-id>";
Deno.cron("nightly-etl", "0 2 * * *", async () => {
try {
await runJob();
await fetch(PING);
} catch (err) {
await fetch(`${PING}/fail`, {
method: "POST",
body: String(err).slice(0, 10_000),
});
throw err;
}
});
Deno Deploy and external cron vs. Deno.cron
On Deno Deploy, Deno.cron runs inside the isolate
and is the recommended approach. For scripts invoked externally by
a system cron, use the same
try/catch pattern but wrap the top-level await call
rather than a Deno.cron handler. See also the
Node.js guide for a comparison
and the LastPing MCP server for AI-agent
provisioning of monitors.
What this catches
The catch reports what it can; the silence reports the rest.
- A thrown error: the
/failping opens an incident immediately with the stack trace stored on the ping event. - An unhandled rejection: if the outer try/catch doesn't catch it, Deno marks the cron run as failed; the absence of a success ping opens the incident.
- Process kill: no ping fires; the missing ping opens the incident after the grace window.
- Deploy failure: new deploy that crashes on startup never registers the cron handler; absence → incident.
- Recovery: the next successful run closes the incident and sends a recovery notice automatically.
Questions people ask
Front-loaded answers: the most important fact first.
-
How do I monitor a Deno cron job?
Use
Deno.cronto register your task. Inside the async handler, wrap your job in try/catch: on successawait fetch('https://ping.lastping.dev/<your-monitor-id>'); on errorawait fetch('/fail', { method: 'POST', body: String(err).slice(0, 10000) })and re-throw. -
Does Deno.cron require any flags in Deno 2?
No.
Deno.cronis stable in Deno 2.x and available without flags. In Deno 1.x (1.38+) it was unstable and required--unstable-cron. Check your Deno version withdeno --version. -
Do I need npm or a third-party package?
No. Deno ships
fetchand the nativeDeno.cronAPI built in. The entire integration is zero-dependency: no npm, no JSR package, no import map entry. -
Does this work on Deno Deploy?
Yes.
Deno.cronis supported on Deno Deploy and runs inside the isolate. Each invocation gets its own execution context, so the try/catch wraps the full body of each tick. -
What if the Deno process is killed?
A killed process sends no ping. Absence-detection monitoring handles this: the missing ping opens an incident after the grace window without any code running on the failure side.
-
Is Deno cron monitoring free?
Yes. LastPing is free for individuals with no monitor cap. See how it compares to Healthchecks.io and Cronitor.
Built-in fetch, native cron, zero setup: just add the ping.
Five lines now beat debugging a silent scheduled task later. First alert wired up in about a minute, and LastPing monitors itself the same way.