The Flawed Panacea: Is 'Everything is an Endpoint' a Recipe for Fragility?
We live in an age of APIs, a world stitched together by remote procedure calls. In our quest for observability, a powerful maxim has taken hold, one that sounds deceptively simple and elegant: "Everything is an endpoint." The logic is seductive. If you can expose a URL, you can monitor it. This approach promises a uniform way to check the health of databases, message queues, cache servers, and even the subtle interplay between microservices. But I want to suggest that this received wisdom, applied too broadly, can lead us to build systems that are ironically more brittle, not less.
The allure is undeniable. By reducing a service's health to a simple HTTP status code, we create a clean abstraction. Our monitoring tools can all speak the same language. A 200 means "go," and a 5xx means "no-go." It’s the systems equivalent of a simple thumbs-up or thumbs-down. This works wonderfully for, well, an endpoint. If your web server's primary job is to serve HTTP requests, then asking it for a `/health` endpoint is a perfectly reasonable check. It verifies the very pathway a real user would take.
But what about the database that backs that server? We reflexively add a dependency check: the `/health` endpoint now pings the database and returns 500 if it can't connect. We've just created our first point of failure inflation. The service itself might be perfectly healthy—its code is running, its memory is managed, its threads are ready. But because it can't reach one single component, it declares itself entirely dead to the world. We've conflated the health of a service with the health of its entire ecosystem. It’s like declaring a car’s engine broken because the fuel gauge is empty; the components are related, but their states are not the same.
This conflation encourages a dangerous architectural posture. When every service’s health check is a distributed transaction in miniature, we create cascading failure scenarios that are difficult to debug and even harder to mitigate. A temporary network blip or a slow response from a non-critical dependency can bring down a perfectly functional service, causing a wave of false alarms that obscures the true root cause. Our elegant, unified health check system becomes a mechanism for spreading panic rather than conveying clarity.
This isn't to say that health checks are bad. The critique is against the oversimplification. True robustness comes from a more nuanced understanding of what "health" means for each component. A database's health might be better measured by its replication lag and connection pool saturation, metrics that an HTTP endpoint can only approximate. A message queue's vitality is in its ability to process and deliver, not just to acknowledge a TCP handshake.
The promise of "everything is an endpoint" is a panacea that treats all ailments with the same medicine. But observability isn't about simplicity; it's about clarity. It requires us to listen to the specific, often complex, symphony of our systems, not just check for a single, uniform heartbeat. Sometimes, the most reliable service isn't the one that shouts "I'm up!" from a single URL, but the one whose many internal signals we've learned to understand in their own unique language.
Notes & further reading
A few pages I came back to while writing this:
- Denver, CO
- The Spinning Plate and the Steadying Tap
- Fort Collins, CO
- The Fallacy of the Silent Engine: Why 'No News' Is the Worst News
- Lakewood, CO
- The Watchman's Hearth: Why the Steadiest Pulse Came from Home
- Thornton, CO
- Bridgeport, CT
- Hartford, CT
- New Haven, CT
- Stamford, CT
- Washington, DC
- Cape Coral, FL