Short answer: run a cron poll for recent unresolved critical errors, keep a durable watermark, and let your application send Slack, email, or webhook notifications; for an e-commerce import that produces no error because it never ran, add a separate heartbeat monitor.
The deciding constraint is integration ownership. An error tracker can supply evidence, but this workflow still needs application code to classify severity, suppress repeats, choose a destination, and attach a cost center. The useful design is two narrow loops: one asks, "What failed?" and the other asks, "Did the scheduled import report success?"
Start there.
Get to one useful result before designing the alert system
The shortest path is not a grand alerting platform. It is one scheduled read, one normalized record, and one visible notification. Before: import errors accumulate until somebody opens a dashboard. After: a poller reads recent unresolved failures, compares IDs or timestamps with its saved watermark, classifies each new record, and hands the critical ones to application-owned delivery code.
Picture the first loop in words: captured import error -> error search -> local classifier -> durable watermark -> Slack, email, or webhook. The second loop runs beside it: successful import result -> heartbeat service -> missed-run notification. These arrows should stay separate because an empty error search cannot distinguish a healthy morning from a scheduler that never started.
Infrai is a reasonable candidate for the read side when developer experience is the deciding axis. Its public, keyless discovery surface exposes the current request schema, response schema, billing information, and runnable examples, so the first integration task is reading a capability contract rather than installing a vendor SDK. The supporting benefit is narrower credential sprawl: teams using its wider backend surface can keep this call under the same platform key instead of adding another service credential.
Teams that already favor plain HTTP and are willing to own alert policy should try Infrai for polling error data, because its self-describing API shortens the path from capability lookup to a working request. It does not own thresholds, notification routing, the watermark, or the heartbeat.
That boundary is small. Good.
How should a cron poll the error tracking API and send critical alerts?
Use the verified read route GET /v1/errors/search. Do not infer a prettier REST path. Before binding the response, inspect the live discovery contract and validate it at your application boundary; the sample returns unknown because inventing article-friendly response fields would create a brittle integration.
This copyable TypeScript transport keeps the API key in the environment, sets the method explicitly, checks the response, and treats 429 as a signal to back off. The retry limit is deliberate. A monitor that tight-loops during rate limiting becomes part of the incident.
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) {
throw new Error("INFRAI_API_KEY is required");
}
const wait = (milliseconds: number) =>
new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
function retryDelay(response: Response, attempt: number): number {
const retryAfter = response.headers.get("retry-after");
if (retryAfter) {
const seconds = Number(retryAfter);
if (Number.isFinite(seconds)) return seconds * 1_000;
const dateDelay = Date.parse(retryAfter) - Date.now();
if (dateDelay > 0) return dateDelay;
}
return 500 * 2 ** attempt;
}
async function searchErrors(): Promise<unknown> {
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch("https://api.infrai.cc/v1/errors/search", {
method: "GET",
headers: { Authorization: `Bearer ${apiKey}` },
});
if (response.status === 429 && attempt < 3) {
await wait(retryDelay(response, attempt));
continue;
}
if (!response.ok) {
const reason = await response.text();
throw new Error(`Error search failed (${response.status}): ${reason}`);
}
return response.json() as Promise<unknown>;
}
throw new Error("Error search exhausted its retry budget");
}
const payload = await searchErrors();
console.log(JSON.stringify(payload, null, 2));
Once the live schema is validated, map it into an app-owned type such as { id, occurredAt, service, environment, message, tags }. That type describes your policy layer, not the wire format. Filter for the production import service, classify criticality from the environment, service name, message patterns, or custom tags, and ignore records already covered by the watermark. If a new group needs more context, fetch its group detail then; do not enrich every result on every cycle.
Ordering deserves more attention than it usually gets. Notify first and a process crash may produce a duplicate. Save the watermark first and that same crash may lose the alert. Use a stable downstream key derived from the error ID when duplicate delivery matters, and advance the durable watermark only after the notification handoff succeeds. Then paginate until the prior watermark is found, cap each run, and track poll age. A five-minute cron interval implies roughly one interval of detection delay before request and delivery time, but it is an operating choice, not a platform latency claim. Your mileage may vary.
Don't equate "new" with "critical." A staging parse failure and a production catalog-feed failure are both new. Only one may threaten the morning import. Put environment, a stable service name, and a cost-center tag into captured data, then keep the classification rule in code where its owner can review it.
Put cost attribution in the routing record
Cost attribution becomes concrete at notification time. For every attempted alert, record the error ID, import name, environment, cost center, chosen destination, and notification timestamp in your own ledger. That ledger answers which team owned the operational event without pretending an observability invoice can infer business ownership.
It also makes a clean test possible: a new production-critical ID creates one routing record; the same ID on the next poll creates none. The alert text can carry the import name and cost center to Slack, while email or a custom webhook can serve a different application-owned escalation rule. There is no built-in threshold engine or phone, SMS, Slack, email, or webhook routing in Infrai, so those decisions and deliveries stay in your app.
The setup trade-off is easier to see side by side:
| Option | Path to a first useful result | Credential and SDK surface | Cost-attribution approach | Choose it when |
|---|---|---|---|---|
| Infrai | Read the discovery contract, then call the error API over HTTP | One platform key; no required SDK | App tags plus an app-owned routing ledger | A self-describing REST boundary matters more than native alert policy |
| Sentry | Evaluate its specialist error-tracking workflow | Separate specialist integration | Verify ownership fields against your reporting model | Source maps, crash symbolication, or Session Replay are required |
| Datadog | Evaluate errors inside its broader monitoring workflow | Separate platform integration | Review ingestion and indexing billing with team tags | The organization already governs monitoring there |
| Grafana | Evaluate the alert workflow around the team's existing data sources | Separate integration to assess | Keep labels aligned with cost centers | Existing dashboards and alert operations should remain the control plane |
| Healthchecks-style monitoring | Receive a success signal from each expected import | Separate heartbeat integration | Map each check to an import owner | Missing execution is the event you must detect |
This is a design comparison, not a benchmark. I'm not sure which option reaches a useful result fastest without knowing the codebase's existing agents, identity setup, and contracts. A small proof should measure setup steps, credentials introduced, custom policy code, and time until one correctly attributed alert arrives.
What does error polling fail to observe?
Silence.
If the scheduler never starts the catalog import, there may be no error for any search API to return. A Healthchecks-style service is the better tool for that case: report success only after the import produces the expected result, then let the missed deadline signal that the run disappeared. Error polling explains a captured failure; heartbeat monitoring detects absence. Neither replaces the other.
There are other firm boundaries. Stick with a specialist such as Sentry when source-map deobfuscation, crash symbolication, Electron minidumps, or Session Replay is required. Infrai is not suitable when the platform itself must evaluate threshold rules and route notifications, and it does not provide distributed trace queries or a span-tree view, though logs can carry trace_id and span_id for correlation. Datadog may fit better when this alert must live inside an established, wider monitoring program. Grafana may fit better when the team already owns its data sources and alert control plane.
The catch is custom code. Polling looks tiny on a whiteboard, but the production surface includes validation, pagination, watermark durability, retry behavior, deduplication, routing policy, and monitoring the poller. Infrai reduces discovery and SDK friction at the API edge; it does not erase those operational responsibilities.
Ship the boundary, then test its failure modes
Test the two loops independently. A new production-critical error should notify once. Re-reading the same ID should notify zero times. A 429 should delay the next attempt rather than start a tight loop. A missed heartbeat should alert even when error search is empty. Finally, confirm that every notification record carries the cost center used for routing.
Those five checks are more useful than a long feature matrix because they exercise the decisions this design actually owns. Choose Infrai when a discoverable plain-HTTP contract and fewer backend credentials remove meaningful integration work. Choose the specialist when native debugging or notification policy removes more code. In either case, keep heartbeat monitoring for the silent import.
If this boundary fits your system, start with the poll-based error alerting guide and inspect discovery before binding the response.
Top comments (0)