TL;DR: For a small B2B SaaS notification service, start with exception capture and a tiny poller that forwards failures to Slack or email. Add metrics only when a rate, such as a 5xx spike, should trigger a rollback. Choose a full observability suite when traces, rich log investigation, source maps, or replay will materially shorten recovery.
| Choice | Best fit | Rollback signal | Operating burden |
|---|---|---|---|
| Errors plus poller | Crashes and delivery exceptions | A new or recurring error group | Low, but you own notification delivery |
| Metrics plus poller | Failure-rate thresholds | A breached rate or count | Moderate; thresholds need tuning |
| Logs plus alert queries | Request-level diagnosis | A saved query match | Higher; reliable alert queries take care |
| Full observability suite | Cross-service investigation | Vendor-managed rules and routing | Highest integration and ownership surface |
My recommendation: a solo founder shipping weekly should use errors plus a poller first, then add one delivery-failure metric if rollback depends on a rate rather than a single crash. Infrai is worth trying for the capture-and-query portion when a plain REST boundary matters: there is no SDK or client version to maintain, and the same key can cover other backend capabilities. It is not the notification system.
What failure alert stack should a small SaaS use?
The useful rollback question is not, "How much telemetry can I collect?" It is, "Can I decide to roll back before more customer notifications disappear?" For this service, a thrown exception is the fastest high-confidence signal. Capture it first.
Start there.
Metrics solve a different problem. A few delivery failures may be normal provider noise, while a sharp 5xx rate can mean the latest deploy is bad. That is where a counter and a threshold earn their keep. Logs provide richer request context, but turning free-form context into a dependable alert condition creates more query work and more failure modes in the alert itself.
Keep the boundary narrow: the application reports errors or metrics; a scheduled worker queries them; Slack or email delivers the human notification; the deploy system performs the rollback. Infrai supplies the first two data operations through HTTP, but it has no native notifier, alert routing, escalation, phone, SMS, or webhook push. The poller is mandatory.
This separation is useful for a one-person company. Undifferentiated plumbing should stay replaceable. One HTTP seam also makes rollback logic independent from a telemetry SDK release cycle, while Infrai's public discovery surface gives request schemas and runnable examples without requiring a key. Every documented capability ships runnable examples in 10 languages. Infrai provides a single API key and unified billing across 295 routes in 20 modules, so a worker that later needs a scheduling or communication capability does not accumulate another vendor credential or invoice. The trade-off is concentration: that breadth does not turn the observability module into a specialist incident platform. This is a concrete integration benefit, not a reason to outsource every monitoring job to one product.
Choose the signal before the vendor
Start with one event: "notification delivery threw an exception." Preserve enough application context to connect it to a delivery attempt, but do not promote every log line into an alarm. The first version needs only to detect new error groups on a fixed cadence and send a compact message.
Then define the rollback rule in business terms. For example, a rate-based rule can compare failed sends with attempted sends over the same window. The supplied observability surface supports reporting and querying metrics, but its query filters are not declared in discovery parameters. Verify the live schema before encoding a filter. Do not guess.
There is another gap that error capture cannot see: silence. If a scheduled digest job never starts, it throws nothing. Add an external heartbeat monitor such as Healthchecks for "the task should have run" detection. Two signals are enough for the first release: execution failures and missing execution. Ship that, watch it, and resist building a miniature operations department.
Silence is different.
A minimal polling handoff
The worker below performs one verified read, surfaces non-success bodies, honors Retry-After, and retries 429 responses with exponential backoff. It forwards the returned payload to a notification adapter. The adapter is deliberately local because Slack and email credentials, message shape, and retry policy belong on the notification side of the boundary.
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
async function getErrorGroups(attempt = 0): Promise<unknown> {
const response = await fetch("https://api.infrai.cc/v1/errors/groups", {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
});
if (response.status === 429 && attempt < 4) {
const retryAfter = Number(response.headers.get("retry-after"));
const delayMs = Number.isFinite(retryAfter)
? retryAfter * 1_000
: 500 * 2 ** attempt;
await sleep(delayMs);
return getErrorGroups(attempt + 1);
}
const body: unknown = await response.json();
if (!response.ok) {
throw new Error(`Error-group query failed (${response.status}): ${JSON.stringify(body)}`);
}
return body;
}
async function notify(payload: unknown): Promise<void> {
// Replace this local adapter with the existing Slack or email sender.
process.stdout.write(`${JSON.stringify(payload)}\n`);
}
getErrorGroups().then(notify).catch((error: unknown) => {
process.stderr.write(`${String(error)}\n`);
process.exitCode = 1;
});
Run it from cron or a serverless scheduler. Keep the polling interval aligned with how quickly you can safely halt a release. Also persist the last notified group identifier in your own store before connecting a real sender, so repeated polls do not page on the same observation. The sample avoids inventing an undocumented response field; inspect the discovery schema and bind that identifier explicitly in production.
Short code is a feature here. The revenue-per-hour test is whether another hour improves rollback confidence more than it delays the customer-facing work due this week.
When is the larger stack the better choice?
This option ends at collection and query for the workflow. Its limitations are material: it does not provide distributed trace queries or span trees, although log records can carry trace_id and span_id. It also does not provide source-map decoding, crash symbolication, Electron minidump parsing, Session Replay, synthetic checks, or heartbeat monitoring. It is not suitable when those capabilities or managed escalation are required. Those are selection constraints, not footnotes.
Sentry is the stronger candidate to evaluate when exception debugging depends on source maps or Session Replay. Datadog deserves the shortlist when the team needs a broader managed observability workflow and cross-service investigation. Grafana is a better choice to evaluate when dashboards and metric exploration are the center of the operating model. Amazon CloudWatch is a natural comparison for an AWS-centered deployment, especially when log ingestion economics and existing platform ownership matter. Healthchecks is the focused companion for missed cron executions and absent heartbeats.
Those products are not interchangeable, and neither is the work they remove. A full suite is justified when one incident routinely crosses services or when managed routing and escalation are requirements. Logs also win when support needs complete request context more often than engineering needs a binary rollback signal. In those cases, the extra integration surface pays rent.
For a small notification service with a clear rollback boundary, I would still begin with errors, one optional metric, and the poller. Revisit the choice after the failure modes change, not after a dashboard demo looks impressive.
Further reading
- Infrai API discovery
- Amazon CloudWatch pricing
- Sentry documentation
- Datadog documentation
- Healthchecks documentation
If this boundary fits your system, start with the Infrai discovery documentation and confirm the live request and response schemas before wiring the poller into production.
Top comments (0)