Guides

Metrics and history

Every job keeps running totals and a capped list of recent runs, so you can see what it has been doing without adding any instrumentation.

On this page
baker.getMetrics("send-digests");
// {
//   totalExecutions: 12,
//   successfulExecutions: 11,
//   failedExecutions: 1,
//   averageExecutionTime: 842,
//   lastExecutionTime: 790,
//   lastError: "SMTP connection timed out",
// }

baker.getHistory("send-digests");
// [
//   { timestamp: Date, duration: 790, success: true, error: undefined },
//   { timestamp: Date, duration: 30012, success: false, error: "SMTP connection timed out" },
//   ...
// ]

Metrics

totalExecutions number
Runs that have finished, successful or not. Skipped ticks aren’t included.
successfulExecutions number
Runs where the callback finished without an error.
failedExecutions number
Runs where the callback threw or rejected.
averageExecutionTime number
The mean duration of all finished runs, in milliseconds.
lastExecutionTime number | undefined
The duration of the latest run, in milliseconds. Not set until a run finishes.
lastError string | undefined
The message from the latest failure. A later success doesn’t clear it, so compare it with the history if you need to know whether the problem is current.
skippedExecutions number | undefined
Ticks skipped by overlap protection. Not set until the first skip.

Durations include onTick and onError, since both are awaited as part of the run.

History

getHistory() returns one entry for each finished run, newest first.

timestamp Date
When the run started.
duration number
How long it took, in milliseconds.
success boolean
Whether the callback finished without an error.
error string | undefined
The error message, if it failed.

A job keeps its last 100 runs by default. Older entries are dropped, but the totals in the metrics keep counting. Change the limit for one job with maxHistory, or for every job on a baker with schedulerConfig.maxHistoryEntries. maxHistory: 0 keeps no history at all.

const baker = Baker.create({
  schedulerConfig: { maxHistoryEntries: 20 },
});

baker.add({ name: "chatty", cron: "@every_second", maxHistory: 5, callback });

Both getMetrics() and getHistory() return copies, so changing the result won’t affect the job.

A status endpoint

Here’s a small report you could return from a health check or an admin page.

import Baker from "cronbake";

export function jobReport(baker: Baker) {
  return baker.getJobNames().map((name) => {
    const metrics = baker.getMetrics(name);
    const [latest] = baker.getHistory(name);

    return {
      name,
      status: baker.getStatus(name),
      nextRun: baker.isRunning(name) ? baker.nextExecution(name) : null,
      lastRun: latest?.timestamp ?? null,
      lastRunOk: latest?.success ?? null,
      failures: metrics.failedExecutions,
      skipped: metrics.skippedExecutions ?? 0,
    };
  });
}

Resetting

job.resetMetrics() clears the totals and history for one job, and baker.resetAllMetrics() does it for all of them.

Turning metrics off

Baker.create({ enableMetrics: false }) makes baker.getMetrics() return zeros and baker.getHistory() return an empty list, and it leaves metrics out of the persisted state.

Jobs still record their runs underneath, and you can reach those numbers directly with baker.getAllJobs().get(name)?.getMetrics(). Think of this option as hiding the numbers, not as a way to save work.

Metrics don’t reliably survive a restart. See what persistence keeps before relying on them.

esc

Try overlap, restore or timezone.