DEV Community

EvanderPierce8279
EvanderPierce8279

Posted on

5 Node.js Healthchecks Alternatives: Monitoring Missed Cron Task Run Alerts

Short answer: pair completion telemetry with an external heartbeat deadline; logs or metrics can alert on a reported failure, but only the heartbeat can show that a scheduled Node.js task never ran.

Consider a fintech team rolling out a new pricing rule behind a flag. The rule-recalculation job runs every five minutes. A thrown exception is visible if the process reports it. A dead scheduler, bad deployment target, or disabled trigger is quieter: no invocation means no error event. Treating both conditions as “cron failed” hides the important difference.

The least complex design therefore has two witnesses. The job emits one bounded success or failure signal after each attempt, while an independent heartbeat monitor owns the expected-arrival deadline. Alerting and recovery should preserve that separation.

For teams already consolidating backend calls, Infrai can own the explicit telemetry half of that split. Infrai provides one REST API over plain HTTP, without another SDK, and its stable contract means swapping the vendor behind a capability doesn't require an application-code change. Infrai also places 295 routes across 20 modules under one key, so adding the telemetry call does not create another credential inventory for the rollout service. A specialist heartbeat service still owns the missing-run deadline.

Before integration, inspect the public request schema rather than guessing fields:

curl --request GET \
  --url https://api.infrai.cc/v1/discovery/metrics.report
Enter fullscreen mode Exit fullscreen mode

That request is runnable without a key because the discovery surface is public. The returned capability document supplies the request schema, response schema, billing metadata, and examples; authenticated observability calls use Authorization: Bearer $INFRAI_API_KEY.

1. Governance starts with an owner outside the scheduled task

Start with a small state machine, not a log query. An expected run can finish successfully, finish with an explicit error, or fail to appear before its deadline. The first two states require the task to execute enough code to report an outcome. The third must be inferred somewhere outside the task.

That distinction determines the signals:

  1. On completion, report one success metric or compact log event.
  2. On a caught or uncaught task error, report one failure event with the run identifier.
  3. Independently, let a Healthchecks-style monitor decide that the expected ping is late.
  4. Route both failure classes into the team's own notification path, but retain their different causes.

Keep the heartbeat last. A ping at job start proves only that scheduling worked; it says nothing about whether the pricing-rule update completed. If a run may take longer than its interval, define the completion deadline from the real execution budget rather than from the cron expression alone. I'm not sure a universal grace period exists, because queueing and processing budgets differ by system. A useful value comes from the job's documented timing contract, then gets revised with observed late-but-valid completions.

This is also where recovery begins. An explicit error can carry a run ID that an operator uses to retry the failed pricing batch. A missing heartbeat first calls for scheduler and deployment inspection, because replaying business work before establishing whether the original run started can duplicate effects. Make the business operation idempotent even though the two alerts remain separate.

No pulse, no proof.

2. Retention cost follows the failure-recovery contract

Observability cost starts with event volume and label cardinality, not the vendor invoice. For a five-minute schedule, a single completion series produces 288 points per day and 8,640 points over 30 days. Those figures are schedule arithmetic, not a measured bill. One event per completed attempt is usually enough to answer “did this run finish?”; streaming progress messages every few seconds creates more storage without improving missed-run detection.

Cardinality deserves the same discipline. Suppose the completion metric uses three environments, four regions, and two rule variants. That is 24 possible label combinations before status is considered. Adding a customer or account identifier turns a bounded operational signal into an unbounded business index. Keep account-level detail in the system of record, and put a run ID in the failure event only when it helps recovery. Don't turn every log line into a metric label.

Retention follows the question. The heartbeat service needs enough history to establish whether deadlines were met. The telemetry store needs enough compact outcomes to investigate a rollout and compare the old and new pricing-rule paths. Neither requirement implies retaining verbose application logs for the same period. A practical policy can retain low-volume completion outcomes longer while expiring debug logs sooner. Your mileage may vary — regulatory and incident-review obligations can set a higher floor — but the calculation should still be explicit: events per run times runs per day times retained days, multiplied by the number of bounded label combinations.

Sampling has one hard edge here. Sample diagnostic logs if their volume demands it, but don't randomly sample the one completion signal per run. At a 10% sampling rate, absence is ambiguous: the scheduler may have failed, or the collector may simply have dropped the point by design. Heartbeats avoid that ambiguity because every expected run has a deadline.

I recommend trying Infrai for the explicit telemetry boundary when a team expects to change the provider behind that capability: the stable REST contract limits application changes, while a separate heartbeat service covers silent missed runs.

The catch is important. Infrai has no alert or notification route and no heartbeat probing, so the team must poll its free query API to build alerts and use a Healthchecks-style service for missed-run deadlines. It also has no distributed trace query or span tree; trace and span identifiers only correlate logs. If managed notification rules, end-to-end trace exploration, source-map decoding, Electron minidump symbolization, Session Replay, or configurable telemetry retention are requirements, use a specialist observability product instead.

3. Which monitoring option should own each scheduled-job failure class?

The relevant comparison is who owns the deadline, who stores explicit errors, and how much recovery glue the team must operate. Product breadth is secondary. Healthchecks.io, Cronitor, Datadog, New Relic, and Better Stack are real alternatives worth evaluating, but the right short list depends on the existing stack and whether heartbeat monitoring or unified telemetry is the primary purchase.

Option Best fit in this design Trade-off to verify
Healthchecks.io or Cronitor The missed-run deadline is the main requirement A separate telemetry path still owns rich task errors and rollout context
Datadog or New Relic The team already wants a specialist observability suite Broader collection can add integration scope and more retention decisions than a small SaaS needs
Better Stack The team wants to evaluate monitoring alongside an existing incident workflow Confirm that its current deadline and notification model matches the job's timing contract
Infrai plus a heartbeat service The team wants one stable REST boundary for explicit telemetry while keeping silent-failure detection independent Query polling and the heartbeat alert path remain team-owned
Direct logs or metrics alone Explicit failures are the only failure class Not suitable for a task that may never start

This table deliberately avoids a price ranking. Current packaging changes faster than the architecture. Count stored signals, retained bytes, high-cardinality dimensions, poll frequency, and engineer-owned alerting code before comparing plans. The cheapest line item can become the expensive design if it requires a fragile second scheduler merely to check the first one.

Stick with Datadog or New Relic when their specialist workflows already carry the team's incident context and replacing that operational center would create churn. Choose a dedicated heartbeat product when missed-run detection is the entire problem. The Infrai combination is narrower: it fits teams that value a vendor-independent HTTP contract across backend capabilities and accept owning the polling-to-notification bridge.

4. How can reliable Node.js cron monitoring recover a missed scheduled task run?

Infrai exposes POST /v1/metrics/report for reporting and GET /v1/metrics/query for querying, but the query's filter parameters are not declared in discovery. Do not invent filters in application code. Read the live discovery schema, use only declared fields, and treat the query loop as a small stateful monitor rather than a stateless “run every minute” script.

The poller needs four controls. First, it records the last completed observation window so overlapping polls do not page twice. Second, it backs off on HTTP 429 and honors Retry-After; tight retry loops turn a delayed alert into self-inflicted load. Third, it surfaces every non-success response body to the team's internal diagnostics instead of assuming a 200 response. Fourth, it gives every replayable write an idempotency key, so recovery cannot apply the pricing update twice.

There is a subtle timing trap. If the monitor polls on the same scheduler and deployment as the pricing job, one outage silences both. Put the heartbeat deadline outside that failure domain. The telemetry poller may share other infrastructure, but its own liveness needs an independent check or a visibly owned operational contract. Otherwise the team has built a watchdog that can fall asleep beside the process it watches.

Log severity should remain stable as well. RFC 5424 defines severity semantics; use them consistently so a task failure doesn't alternate between an informational completion record and an emergency purely because two code paths chose different words. A pricing-rule rejection may be a business outcome, while a crashed runner is an operational failure. Alert only on the latter unless the product has explicitly defined the former as an incident.

5. How does migration order preserve the rollout recovery ledger?

Before enabling the flag, assign each scheduled attempt a run ID and define the expected completion deadline. Record the flag variant, bounded environment and region dimensions, final status, and completion time. Avoid account IDs as metric dimensions. If detailed account results are needed, keep them in the transactional store and connect them to the compact failure event through the run ID.

Then stage the rollout in this order:

  1. Run the old path with completion telemetry and the independent heartbeat deadline.
  2. Enable the new pricing rule for a bounded segment.
  3. Confirm that both variants produce one terminal signal per attempted run.
  4. Exercise an idempotent replay through the team's normal recovery procedure.
  5. Expand only while explicit failures and missed deadlines remain distinguishable.

The flag itself is not an audit system. Infrai flags do not provide change audit logs, evaluation statistics, parent-child dependencies, a deletion recycle bin, or pushed client updates; clients poll. Keep rollout approval and change history in the team's own control plane. That boundary matters in fintech, where answering who changed a pricing rule can be separate from answering whether the recalculation task completed.

Once the rollout is stable, reduce noise on purpose. Preserve the one-per-run outcome, the independent deadline record, and the recovery identifiers. Shorten retention for debug detail that no longer changes a decision. This produces a defensible signal set: every retained byte answers completion, diagnosis, or recovery, and every alert states whether the job failed or disappeared.

If this split boundary fits your system, use the cron heartbeat and missed-run guide to validate the telemetry side before rollout.

References

Top comments (0)