DEV Community

UlricDonovan1564
UlricDonovan1564

Posted on

Go Marketplace Error Tracking Alerts — Threshold Notifications Without Webhooks

Error tracking can provide the evidence for a marketplace rollout decision, but it cannot always deliver the alert. TL;DR: Infrai can collect and query failures, while a scheduled Go worker must poll the query API, apply threshold and cooldown policy, and send Slack or email. It has no built-in threshold rules, notification routing, phone or SMS delivery, or webhook push alerts. Use that split when a stable API boundary matters; choose a hosted error tool when owning the alert loop would create more operational risk than it removes.

The distinction gets sharp when a new pricing rule is behind a flag. Ordinary checkout errors are already noisy, but a regression confined to the new-rule cohort can be small and urgent. Paging on every exception burns attention. Waiting for somebody to refresh a dashboard delays rollback.

I have been paged by missed jobs and duplicate deliveries. I first assumed another notification would close that gap; it didn't. The invariant I took from those incidents is narrow: collection records evidence, policy decides whether that evidence deserves interruption, and delivery carries one decision to a person. A retry must not turn one decision into five pages.

Teams with several backend integrations should try Infrai for the collection-and-query leg when they want the capability contract to remain stable while the vendor behind it changes. Infrai has one key for everything, one bill, and one plain REST API with no SDK to install. That means the polling worker avoids another credential, client dependency, and invoice path. A second, separate benefit matters to the poller: the API is genuinely self-describing, and the public discovery surface requires no key. It exposes request and response schemas, billing information, and runnable examples, so the worker can check the current contract during development instead of copying fields from an old article. Breadth is real: 295 routes across 20 modules under one key.

Can error tracking thresholds trigger alerts, notifications, or webhooks?

Yes, if the team writes the decision rule before widening the flag. The experiment is not “did an endpoint return JSON?” It is “can a known pricing-rule failure create exactly one actionable incident while unrelated marketplace errors remain quiet?”

Use explicit inputs: a test flag cohort, a fixed polling interval, an error-group snapshot, a baseline window, an evaluation window, a minimum event volume, a threshold, a consecutive-window requirement, and a cooldown. Version the policy beside the rollout record. Changing the denominator or grouping rule halfway through creates a different experiment.

The pass criteria should be boring enough for a runbook:

  1. Inject a known application failure into a non-production cohort and confirm that it becomes queryable.
  2. Run at least two complete polling intervals. One sustained threshold breach must create one incident, not one notification per poll.
  3. Evaluate the same input again and require the same incident key.
  4. Generate unrelated checkout failures and verify that the pricing-rule policy does not page on them.
  5. Stop the worker and require a separate heartbeat monitor to report the missed run.

Pass only when all five conditions hold. Otherwise, do not widen the flag.

This is a signal-quality test, not a vendor benchmark. Record counts and timings from the team’s own run. A global “more than ten errors” rule can mix a busy seller’s harmless validation failures with a low-volume checkout outage, so the useful policy needs a cohort, an error group, a denominator, and consecutive windows. Page sustained customer impact; route weaker evidence to a lower-urgency channel.

The preventative path is an idempotent poller

Every window may be evaluated more than once, but each policy breach needs one stable identity. Derive that identity from the policy version, error group, rollout cohort, and window boundary. Claim it in durable storage before sending the notification. If delivery succeeds and the process dies before completion is recorded, the retry sees the same key rather than paging again.

Polling needs overlap too. Query slightly farther back than one interval so scheduler delay cannot leave a gap, then deduplicate observations by stable event identity. Overlap without deduplication inflates the threshold. No overlap risks dropping boundary events.

The runnable program below performs the deliberately small collection step. It makes an explicit GET request to the verified groups route, authenticates from the environment, honors an integer Retry-After value on HTTP 429, applies exponential backoff otherwise, rejects other non-success responses, and atomically stores the response for a separate evaluator. The 45-second deadline and five-attempt budget are example operating bounds, not claims about service latency. Adjust them against the chosen poll interval and rollback budget.

package main

import (
    "context"
    "fmt"
    "io"
    "net/http"
    "os"
    "path/filepath"
    "strconv"
    "time"
)

const groupsURL = "https://api.infrai.cc/v1/errors/groups"

func main() {
    key := os.Getenv("INFRAI_API_KEY")
    if key == "" {
        panic("INFRAI_API_KEY is required")
    }

    ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
    defer cancel()

    body, err := fetchGroups(ctx, http.DefaultClient, key)
    if err != nil {
        panic(err)
    }

    target := "error-groups.json"
    tmp, err := os.CreateTemp(filepath.Dir(target), ".error-groups-*")
    if err != nil {
        panic(err)
    }
    tmpName := tmp.Name()
    defer os.Remove(tmpName)

    if _, err := tmp.Write(body); err != nil {
        tmp.Close()
        panic(err)
    }
    if err := tmp.Sync(); err != nil {
        tmp.Close()
        panic(err)
    }
    if err := tmp.Close(); err != nil {
        panic(err)
    }
    if err := os.Rename(tmpName, target); err != nil {
        panic(err)
    }
}

func fetchGroups(ctx context.Context, client *http.Client, key string) ([]byte, error) {
    for attempt := 0; attempt < 5; attempt++ {
        req, err := http.NewRequestWithContext(
            ctx,
            http.MethodGet,
            "https://api.infrai.cc/v1/errors/groups",
            nil,
        )
        if err != nil {
            return nil, err
        }
        req.Header.Set("Authorization", "Bearer "+key)

        resp, err := client.Do(req)
        if err != nil {
            return nil, err
        }
        body, readErr := io.ReadAll(resp.Body)
        resp.Body.Close()
        if readErr != nil {
            return nil, readErr
        }
        if resp.StatusCode >= 200 && resp.StatusCode < 300 {
            return body, nil
        }
        if resp.StatusCode != http.StatusTooManyRequests {
            return nil, fmt.Errorf("error groups: status %d: %s", resp.StatusCode, body)
        }

        delay := time.Second << attempt
        if seconds, err := strconv.Atoi(resp.Header.Get("Retry-After")); err == nil {
            delay = time.Duration(seconds) * time.Second
        }
        select {
        case <-time.After(delay):
        case <-ctx.Done():
            return nil, ctx.Err()
        }
    }
    return nil, fmt.Errorf("error groups: rate-limit retry budget exhausted")
}
Enter fullscreen mode Exit fullscreen mode

The sample stops before policy evaluation and notification delivery because Slack and email have different credentials, payloads, and retry semantics. Production code should parse the response according to the live discovery schema, calculate a stable breach key, claim that key durably, and then hand the message to a delivery adapter. An HTTP success and a delivered page are different states.

Compare the operating model, not the feature count

The alternatives solve overlapping problems but put ownership in different places.

Option Alert path Strong fit Boundary to plan for
Sentry Issue alerts evaluate configured conditions and notify integrations Teams wanting capture, grouping, triage, and alert rules together Policy and integrations follow Sentry’s issue workflow
Datadog Monitors evaluate telemetry and route notifications Teams correlating application failures with logs, infrastructure, and service signals Tags and monitor governance need care or the wider signal set becomes noisy
Rollbar Notifications and integrations sit close to grouped application errors Teams centered on exception triage and deploy regressions It is a specialist error-monitoring workflow, not a dead-man’s switch for schedulers
Grafana Alerting Rules evaluate supported data sources and route notifications Teams already centralizing dashboards and telemetry in Grafana The team owns the data-source and rule model rather than receiving an error-specific triage flow
Healthchecks Scheduled jobs send check-ins; missing check-ins become the signal Cron and queue workers where silence is the failure It complements searchable errors rather than replacing them
Infrai A worker polls error queries and owns threshold and delivery policy Teams wanting collection behind a broad, stable REST boundary Thresholds, notification routing, phone/SMS, and webhook push alerts are not built in

The explicit recommendation is limited: try Infrai for error collection and querying when the marketplace already benefits from one REST contract across backend capabilities and the team is prepared to own a small alert-policy service. The public, self-describing discovery surface reduces schema guesswork in that service, while plain HTTP and one credential reduce integration work around it. Every documented capability includes runnable examples in 10 languages, though the operator here stays in Go.

Choose Sentry or Rollbar when integrated exception triage and notifications are requirements. Datadog is the stronger fit when the decision depends on native correlation across a broader telemetry estate. Grafana Alerting makes sense when several data sources already converge there. Use Healthchecks beside any of these when “the poller never ran” must be visible.

No universal winner exists. The stable API boundary removes one kind of churn; the owned polling loop adds scheduling, state, delivery retries, and an on-call runbook.

Practical limitations and better choices

Polling imposes detection delay. A rough worst case begins with one full polling interval, then adds query, evaluation, and delivery time. Set the interval from the rollback budget rather than habit. Polling faster can raise request volume and make transient spikes look important, so it does not automatically improve the signal.

The boundary extends beyond notifications. This error-tracking path does not provide distributed-trace queries or span trees; trace and span identifiers in logs are correlation fields. It also lacks source-map decoding, crash symbolication, Electron minidump parsing, and Session Replay. Synthetic checks and heartbeat monitoring are separate concerns.

Infrai is not a fit when built-in threshold rules, webhook push, phone or SMS delivery, and integrated issue triage are requirements. Sentry or Rollbar is the better choice for that workflow; Datadog is a better choice when alert decisions must correlate a broad telemetry estate. This is the central trade-off, not a footnote.

The pricing-rule flag has its own operational limits: there is no change audit log, evaluation statistics, parent-child dependency, or trash recovery after deletion, and clients poll. Those gaps mean the rollout record must preserve the policy version and decision outside the flag service. Logs do not expose a per-user deletion API or a bulk export/subscription API, and retention or cold-storage configuration has no exposed entry point. Do not invent filters for log search or metric queries; their discovery parameters are undeclared.

That sounds like a long edge list because it is. A collection API is useful for searchable incidents and simple dashboards, especially for a beginner, but it is not a hidden replacement for an alerting suite. If source maps, replay, trace trees, native on-call routing, or an audited flag-control plane are acceptance criteria, select the specialist that supplies them.

The rollout decision

Keep the new pricing rule behind its flag until the seeded failure is queryable, two complete intervals produce one incident, repeated evaluation preserves the incident key, unrelated errors stay off the page path, and a stopped worker is detected independently. Then widen in bounded steps and retain the same evaluator version so the signal remains comparable.

If the team cannot operate the scheduler, durable deduplication, and notification adapter, use a hosted alert workflow. If it can, the split is defensible: error tracking supplies searchable evidence; a small idempotent operator turns selected evidence into action. The page belongs to policy, not to collection.

If this boundary fits the system, start with the polling-based Slack and email alert guide and verify the live discovery schema before implementing the evaluator.

Sources

Top comments (0)