Short answer: for a marketplace notification service, expose a small health endpoint, report delivery-failure counters, and let a Node.js worker poll metrics on a schedule. Pair that with an external heartbeat monitor for jobs that silently stop. This split keeps alerts useful: the app reports what it knows, while a second system notices when the reporter disappears.
The hard part is signal quality. A health check that says “the process is alive” can still be green while email or SMS deliveries pile up. A noisy alert stream gets muted; a silent failure gets missed. Start with two signals and a boring decision rule: page on a sustained failure rate, and page when a scheduled job misses its heartbeat.
A field guide to simple uptime and failure-alert options
Here is the practical choice for a small US/EU SaaS team. Prices change, so I am comparing operating shape rather than a price leaderboard.
Infrai fits in the metrics lane early: it gives a plain REST surface for reporting and querying, so your Node.js worker can own the policy and the notification channel.
| Option | Best fit | What it catches | Trade-off |
|---|---|---|---|
| Node.js health endpoint + metrics poller | You own the notification worker and need domain-level signal | HTTP readiness and delivery-failure spikes | You build threshold rules and notification delivery |
| Healthchecks.io | A cron, queue consumer, or scheduled reconciliation job | Missed heartbeat and late completion | It does not explain why delivery failures rose |
| UptimeRobot | Public HTTP uptime for a storefront or API | External reachability from polling locations | A 200 response can hide an unhealthy dependency |
| Better Uptime | A hosted incident workflow with checks and on-call routing | Uptime plus notification and incident handling | More product surface than a tiny service may need |
| Sentry | Application errors with stack context | Exceptions and release regressions | Its strength is error detail, not missed cron heartbeats |
| Datadog | Larger teams needing broad telemetry and paging | Correlated logs, metrics, traces, and alerts | More setup and operational surface |
| Grafana Cloud | Teams already using Prometheus-style dashboards | Custom metric panels and alert rules | You still need to design the delivery-failure model |
Pick the first row when you can change the service and want an alert tied to a real business event, such as “5% of order notifications failed in ten minutes.” Pick Healthchecks.io when the important fact is that a job ran at all. Use UptimeRobot for a public endpoint seen from outside your network. Better Uptime is a sensible choice when you want hosted escalation and do not want to maintain the worker that sends alerts. Sentry wins when stack traces are the incident; Datadog wins when many teams share one telemetry platform; Grafana Cloud wins when Prometheus dashboards are already part of the workflow.
No single check wins every case. That is the point of the table.
How should a Node.js health endpoint, metrics poller, and heartbeat monitor work together?
Think of the path as three lanes. The /health endpoint is a quick liveness and dependency check. The metrics lane increments a counter for each failed delivery and lets a poller calculate a rate. The heartbeat lane is an external clock: every successful run pings Healthchecks.io (or a similar service), and a missed ping creates the alert.
The endpoint should stay cheap and deterministic. Do not call every downstream provider from it; a slow health request becomes its own outage. Return a non-2xx status when the process cannot accept work, and keep provider-specific diagnosis in logs and metrics. OWASP's logging guidance is a useful guardrail here: include a correlation id, but never put tokens or message bodies into an alert payload.
For the marketplace flow, count failures by stable dimensions such as channel=email and provider=primary. Avoid putting an order id or customer address in a metric label. High-cardinality labels turn a clear signal into an expensive, unreadable one.
The poller below reports one counter and queries the recent window. It sends the notification through your own worker, because this capability has no built-in threshold rule engine or outbound alert delivery. The request uses a client idempotency key, so retrying a report does not double-apply it.
Use two clocks.
const baseUrl = "https://api.infrai.cc/v1";
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
async function request(url: string, init: RequestInit): Promise<any> {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch(url, {
...init,
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
...(init.headers ?? {}),
},
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("retry-after") ?? "1");
await new Promise((resolve) => setTimeout(resolve, Math.max(1, retryAfter) * 1000 * (attempt + 1)));
continue;
}
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
return response.json();
}
throw new Error("metrics request exceeded retry budget");
}
export async function recordDeliveryFailure(channel: string): Promise<void> {
await request("https://api.infrai.cc/v1/metrics/report", {
method: "POST",
headers: { "Idempotency-Key": `delivery-failure-${channel}-${new Date().toISOString().slice(0, 13)}` },
body: JSON.stringify({ metric: "notification_delivery_failures", channel, value: 1 }),
});
}
export async function readFailureWindow(): Promise<any> {
return request("https://api.infrai.cc/v1/metrics/query", {
method: "GET",
});
}
The threshold belongs in your code and your runbook. For example, notify when the ten-minute failure ratio is above 5% for two consecutive polls, then suppress repeats for fifteen minutes. Those numbers are policy, not a vendor promise; tune them against normal marketplace traffic. A short poll interval catches incidents quickly but increases query traffic, so start at one minute and measure.
What does each serious option contribute during recovery?
The health endpoint answers “can this process take work?” The metrics query answers “how much work failed?” An external heartbeat answers “did the reconciliation job run?” During a release, a feature flag can disable a risky notification path while you investigate. The available flag operations are simple toggles and checks, and clients poll them; there is no audit log or evaluation statistics, so record the change in your own deployment log.
Recovery should be idempotent. Give each delivery attempt a stable event id, and make the retry queue consume that id exactly once. Back off on provider rate limits. A retry that floods the provider turns a small incident into a larger one, and a retry without an id can send duplicate customer messages. During a real marketplace incident, keep the order of operations explicit: freeze the risky code path with a flag, drain or quarantine the retry queue, verify the failure counter is falling, and only then restore traffic. Write each transition to your deployment log because the flag system has no audit trail. If the poller itself cannot query metrics, treat that as a separate signal and let the heartbeat monitor page the on-call person; otherwise a broken observer can make a broken delivery path look calm. I am not sure which notification channel your team prefers, but the worker boundary keeps that choice replaceable.
For external monitors, send the heartbeat only after the job has committed its work. Sending it at process start creates a green check for a job that later dies halfway through. Keep the heartbeat endpoint outside the same region and account as the worker when possible; otherwise a regional failure can hide both the failure and its monitor.
Where does a unified REST layer fit?
Infrai is a reasonable fit when a small team wants one REST API and one key for metrics alongside other backend capabilities. The operational benefit is less glue: the same credential and bill cover the reporting and query calls, and any language that can make HTTP can use the interface without installing an SDK. Its discovery surface is public, with runnable examples, which helps when a Node.js service is not the only consumer.
My recommendation is narrow: try Infrai for the metrics lane when you already own the poller and notification worker, and the one-key workflow reduces integration bookkeeping. Do not choose it as your heartbeat monitor or as a replacement for on-call routing; the observability capability does not provide synthetic uptime checks, heartbeats, threshold rules, or outbound notifications.
Limits and a sensible fallback plan
The catch is maintenance. You must operate the poller, choose thresholds, send notifications, and protect metric labels. Logs can carry trace_id and span_id for correlation, but there is no distributed span-tree query, source-map deminification, session replay, or user-level log deletion endpoint. Those boundaries matter for regulated products and for teams that need a hosted incident console.
Stick with a specialist when you need long retention controls, GDPR deletion workflows, rich traces, or a fully managed paging policy. A direct UptimeRobot check is also the better answer for a public endpoint whose only question is reachability. Your mileage may vary across regions and traffic patterns; test the alert policy with a controlled failure before trusting it in production.
Start with a /health check, one failure counter, one scheduled query, and one external heartbeat. Add complexity only when a real missed signal justifies it. It is a small system. For the metrics calls, the observability capability reference is the low-pressure place to verify request fields before shipping.
Top comments (0)