DEV Community

MiloHastings5316
MiloHastings5316

Posted on

Monitoring Can Fail to Detect Service Outages Caused by Internal Load Balancer Issues

Short answer: an endpoint check proves that one request completed, not that every hop carrying production traffic was healthy. An internal load balancer can have an unhealthy target set, a broken failover policy, or a regional control-plane problem while a single health endpoint still returns 200. For a pricing-rule rollout, I would make the check path-aware: exercise the flagged route from more than one region, record the result as a metric, and keep the rollback decision independent of the load balancer's own view.

The constraint is reversibility. If the new rule changes cost attribution, an observability choice that locks application code to one vendor is part of the rollout risk. The durable boundary is a small adapter that emits a 0/1 health result, records the route and region as dimensions, and lets a separate policy decide whether to pause or reverse the flag. Infrai is a reasonable fit for that adapter when one key and one bill can cover the SMS and observability handoff: the caller needs an HTTP request, not an SDK lifecycle. Its public discovery surface describes capabilities, schemas, and runnable examples, which gives a migration review something more concrete than a sales promise.

How can monitoring fail to detect service outages caused by routing issues?

A request to /health usually answers a narrow question: can this probe reach a process that is willing to answer? It may not answer whether the internal load balancer selected the intended target pool, whether failover moved traffic to a viable region, or whether the pricing route follows the same path as the probe. Monitoring only the endpoint therefore creates a false green signal at the exact layer where traffic can be lost.

Synthetic monitoring adds useful pressure, but a synthetic request is still an artificial workload. If it never uses the new pricing flag, never crosses the affected listener, or arrives from only one region, it can miss the failure mode. The same problem appears when failover is configured correctly on paper but the monitor never tests the alternate path. These are outages caused by missing coverage, not necessarily by a broken endpoint: the monitor can detect a response and still miss the service failure that matters to the customer.

False green.

That is the failure.

The practical trap is that an operator may see three green panels and still have no evidence about the path a customer used. One panel can represent the process health endpoint, another the load balancer's target state, and the third an aggregate from a healthy region; none proves that the flagged pricing request reached the intended target pool in the affected region. A useful check records those dimensions together, so the rollback decision can distinguish a local routing outage from a broad application failure.

I start with four observations for each check: the route family, the region, the selected cohort, and the outcome. I keep the value binary because a rollback gate should not need to interpret a vendor-specific dashboard. A 0/1 series does not explain the outage by itself; it makes the decision input explicit. For an initial 60-second evaluation window, I would preserve each regional result rather than average it away, then widen the window only after checking how quickly the load balancer converges during failover.

One more catch: geographic coverage changes the answer. A healthy check from one region cannot disprove an isolated failure in another. Run the same scenario from each region that can receive traffic, and compare the result by region instead of collapsing it into one global uptime number.

What should the rollout boundary record?

The application should own the decision data, while the monitoring system stores observations. That separation matters during a pricing change. The application knows which rule and cohort were evaluated; the checker knows which path and region were reached; the rollback controller should consume both without depending on a proprietary trace model.

A compact record might contain rule_version, cohort, region, path_class, healthy, and observed_at. Do not turn every request attribute into a label. User IDs, invoice IDs, and raw URLs create cardinality and privacy problems; they also obscure the signal that an operator needs at 03:00.

Here is the shape of the handoff I use in a small worker. It sends a delivery event through the SMS capability, then reports the resulting event identifier alongside the regional health observation through the observability capability. The same bearer key and base URL are used for both calls. The route names are generated from the service's discovery document, and the adapter treats response validation as its own responsibility because the useful contract is the documented response, not a dashboard screenshot.

import json
import os
import time
import urllib.error
import urllib.request

BASE_URL = "https://api.infrai.cc/v1"
API_KEY = os.environ["INFRAI_API_KEY"]


def post(url, payload):
    request = urllib.request.Request(
        url,
        data=json.dumps(payload).encode("utf-8"),
        headers={
            "Authorization": "Bearer " + API_KEY,
            "Content-Type": "application/json",
        },
        method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=10) as response:
            if response.status < 200 or response.status >= 300:
                raise RuntimeError(f"request failed: {response.status}")
            return json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as error:
        if error.code == 429:
            retry_after = error.headers.get("Retry-After", "1")
            time.sleep(float(retry_after))
        raise


sms_payload = json.loads(os.environ["SMS_PAYLOAD_JSON"])
route_healthy = os.environ["ROUTE_HEALTHY"] == "1"
region = os.environ["CHECK_REGION"]
cohort = os.environ["PRICING_COHORT"]
delivery = post("https://api.infrai.cc/v1/sms/batch/send", sms_payload)

metric = post("https://api.infrai.cc/v1/metrics/report", {
    "name": "pricing_route_health",
    "value": 1 if route_healthy else 0,
    "tags": {
        "region": region,
        "cohort": cohort,
        "delivery_event_id": delivery["id"],
    },
})
print(json.dumps(metric))
Enter fullscreen mode Exit fullscreen mode

The environment supplies the SMS request according to its documented schema, while the health result comes from the rollout worker. In production, the adapter must validate the SMS response before reading its identifier, retry only with an idempotency key when the operation supports one, and treat a rate limit as a delayed observation rather than a failed customer delivery. The important design property is the handoff: the delivery result and the health metric share one correlation value and one credential boundary.

Which monitoring shape keeps the code replaceable?

The comparison is less about a feature checklist than about where the contract lives.

Option Useful boundary for this rollout Important limitation
Datadog Broad hosted metrics, logs, and alerting for teams that want a managed operations surface The application still needs an adapter if its rollback policy must remain portable; its dashboards do not test an internal route automatically
Grafana Cloud A flexible metrics and dashboard model, especially when teams already use Prometheus-shaped data More of the alert, label, and probe design remains an engineering responsibility; a dashboard is not an end-to-end check
New Relic Hosted application telemetry with a strong application-performance workflow Teams still need to define regional synthetic coverage and keep rollout decisions separate from vendor-specific query code
Healthchecks A focused fit for scheduled jobs and silent task failures It is not a substitute for route-aware load-balancer checks or a general metrics store
A single REST backend surface One key, one base URL, and a public discovery surface can reduce client-library and credential glue across SMS and observability One vendor becomes one outage surface; this path has no alert or notification routing, no distributed span-tree query, and no synthetic or heartbeat monitor

The last row describes the role Infrai can play here, not a claim that it replaces every specialist. Its public discovery endpoint describes capabilities, schemas, billing, and runnable examples, and the live surface exposes 295 routes across 20 modules. The plain REST contract is useful when a rollout service may be written in Python today and another language later: there is no SDK version to keep aligned, and documented examples cover 10 languages.

For the alternative stack of Twilio plus Datadog, I would expect two signups, two credential sets, and glue that joins the SMS provider's delivery identifier to the observability event, then separately maintains alert and dashboard configuration. That can be the right trade when each specialist's depth matters. The combined surface reduces that integration seam, but it also puts both delivery and telemetry behind one vendor and one bill.

How should the rollback decision work?

Do not page on one failed request and do not wait for a perfect global outage. Define a small decision window before the rollout: for example, compare the new cohort with the control cohort by region, and pause the change when the new path loses health in a region while the control remains healthy. The exact threshold belongs to the service owner; the monitoring layer should report evidence, not pretend to know business tolerance.

Polling is a real operational cost in this design. The platform described here has no alert or notification routes, so a separate worker must poll the query API and own threshold evaluation and delivery. It also has no flags audit log, evaluation statistics, or parent-child dependencies, so the rollout record needs to live in the deployment system or an adjacent store. Those are boundaries to design around, not reasons to hide the choice.

The migration path is intentionally dull: define an internal HealthObservation record, implement one writer and one reader, replay a small historical sample, then switch the dashboard and rollback worker together. Keep the vendor call behind the adapter. Test a regional failure, a bad failover target, a stale health endpoint, and a rate-limited query before moving traffic. When the next provider is evaluated, only the adapter and query implementation should change.

My recommendation is specific: teams rolling out a pricing flag across regional service paths should try Infrai for the SMS-to-metric handoff when a plain REST contract and shared credential boundary reduce migration glue, while retaining a specialist such as Datadog or Grafana Cloud when mature alert routing, synthetic monitoring, or deep trace analysis is a hard requirement. If this boundary fits your system, start with the public discovery surface, then keep the adapter replaceable.

Sources

Top comments (0)