Australian cloud for business software — built and run in Sydney since 2003

NetLeverage
NetLeverage

Server Up, Application Unusable: Build Better Health Checks

Technical article
Hosting

A useful health check must measure the operation users need, with separate signals for process liveness and readiness. In ASP.NET Core 8, both Healthy and Degraded return HTTP 200 by default; Unhealthy returns 503 S2. A monitor that accepts any 200 can therefore miss a declared degraded dependency.

This article is source-researched design guidance, not an implemented monitoring system. ASP.NET Core 8 provides a concrete reference for health-check concepts, but no application, probe or infrastructure configuration was changed or tested.

Begin with the user’s required operation

Choose a narrow operation that represents useful service: authenticate and retrieve an authorised document, open a known test record, or complete a controlled synthetic transaction. Define the required response and the dependencies that must work.

A ping or open TCP port establishes infrastructure reachability, not the required application operation.

Microsoft recommends functional dependency checks alongside metrics, logs and traces S1.

Write the acceptance contract before implementing a check. Include the expected status or response, allowed duration, dependencies, data access and what a failure should trigger. These are workload-specific decisions, not universal thresholds supplied by this article.

Separate liveness from readiness

A liveness check asks whether the process is functioning at its basic execution boundary. A readiness check asks whether the instance can accept the intended work. The appropriate response to failure may differ.

For example, an application still loading required configuration may be alive but not ready for traffic. Restarting it repeatedly during that legitimate startup process can prevent it from ever becoming ready. Microsoft’s ASP.NET Core health-check guidance uses this distinction when describing separate readiness and liveness probes.

Likewise, a shared database outage should not automatically cause every application instance to restart in a loop. The remediation design must distinguish a failed local process from an unavailable dependency that restarting the process cannot repair.

Record what each endpoint checks and what it intentionally excludes. A shallow process check and a dependency check can both be useful when their names and operational consequences are explicit. Problems arise when a shallow result is presented as complete application availability.

Understand the framework’s default behaviour

ASP.NET Core can expose a basic health endpoint by registering health-check services and mapping an endpoint. Microsoft states that, by default, no specific dependency or subsystem checks are registered. An application that can answer the endpoint is considered healthy under that basic configuration S2.

That default is an important boundary. The presence of a health URL does not prove that SQL, file storage, authentication or the business workflow is checked. Inspect the registered checks and their selection for each endpoint.

For an existing application, ask the development owner to identify the actual health-check registrations, timeout behaviour, response writer and status mapping. Compare them with the monitoring system’s interpretation. A monitor expecting any successful HTTP status may miss a degraded result represented in the body.

The reference page is rolling documentation and includes multiple implementations and integrations. Match its relevant sections to the application’s installed framework and packages. Do not install a third-party health-check library merely because it appears in a documentation example.

No executable application configuration is supplied here. The design must first establish endpoint access, probe identities, dependency permissions and the actions attached to each result.

Make endpoint selection explicit and cover third-party apps

Untested ASP.NET Core 8 integration fragment, for an existing application with authentication, authorisation services/middleware and a restricted MonitorRead policy already configured S2. It illustrates startup readiness only; the application owner must add bounded dependency checks tagged ready and verify failure behaviour before use.

using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;

// Before builder.Build(), in the existing application's Program.cs:
bool startupComplete = false;
builder.Services.AddHealthChecks().AddCheck("startup",
    () => System.Threading.Volatile.Read(ref startupComplete)
        ? HealthCheckResult.Healthy()
        : HealthCheckResult.Unhealthy("Starting"),
    tags: new[] { "ready" });

// After app is built; retain the existing authentication middleware:
app.Lifetime.ApplicationStarted.Register(() =>
    System.Threading.Volatile.Write(ref startupComplete, true));
app.MapHealthChecks("/health/live", new HealthCheckOptions {
    Predicate = _ => false
}).RequireAuthorization("MonitorRead");
app.MapHealthChecks("/health/ready", new HealthCheckOptions {
    Predicate = check => check.Tags.Contains("ready"),
    ResultStatusCodes = {
        [HealthStatus.Healthy] = StatusCodes.Status200OK,
        [HealthStatus.Degraded] = StatusCodes.Status503ServiceUnavailable,
        [HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable
    }
}).RequireAuthorization("MonitorRead");

This is not a standalone application or database probe. Liveness excludes registered checks; readiness selects tagged checks and maps Degraded to 503. ApplicationStarted indicates framework startup, not completion of arbitrary background initialisation. The owner must use the real readiness condition. Both endpoints require an authorised monitor; test 401/403 separately from health failures. No secrets or detailed exception response are included.

If software is supplied by a third party, start with its supported health endpoint and external synthetic checks: expected page content, response time, DNS resolution and TLS expiry, sampled from representative user locations S1. A public landing page cannot prove login or a protected workflow. Agree an isolated test account and safe transaction with the software owner if deeper evidence is required; never submit real customer orders just to create an alert test.

For either audience, configure what Degraded means operationally: change the status mapping as above or have the monitor interpret an agreed response body S2. Rehearse dependency failure and recovery; a green deployment response alone does not validate the contract.

Choose checks that answer a specific question

A database connection test can establish that the application can authenticate and open its configured database under the tested identity. It does not prove that a required table, stored procedure or business record is usable.

A query can test more, but it also consumes database resources and may expose data. Microsoft warns that health queries can overload the database and recommends keeping any necessary query simple and quick S2. Do not run an expensive report or full integrity check on every probe.

For file dependencies, define a controlled location and the required operation. A directory listing proves something different from an application’s ability to open its specific configuration or safely create a temporary test file. Use synthetic data and an explicit cleanup design if writes are necessary.

For authentication, identify whether the probe checks the real external entry point or only a local service identity. A probe using an administrator account can conceal the access failure experienced by ordinary users.

Keep dependency checks scoped to the functions the instance actually serves. A noncritical reporting dependency may justify a degraded signal while core transaction processing remains available. The service owner must define that classification before the monitor drives routing decisions.

Design synthetic transactions without customer side effects

If a representative operation needs a write, use a dedicated synthetic identity and isolated records supported by the application. Define how the record is recognised, how duplicate execution is prevented where necessary and how cleanup occurs without touching genuine customer work.

Do not submit real payments, emails, orders or integration messages as a routine health test. A probe that creates external effects needs a supported sandbox or an explicitly designed no-effect path. Where that cannot be provided, leave the dependency untested and say so.

Record the transaction’s expected output, not merely whether it returned without an exception. A cached page or generic success response can hide a failed downstream operation. Check an application-specific marker whose meaning the software owner has agreed.

The synthetic workflow is an editorial recommendation. This article does not claim that a particular application or NetLeverage service already supports such an endpoint. Implementation requires the application owner’s design and validation.

Bound load, timing and concurrency

Set a timeout for each check and for the complete probe. Account for retry behaviour in both the application and monitoring system. A slow dependency should not accumulate an unbounded number of health requests during an outage.

Choose frequency from the required detection interval, check cost and number of instances and probe locations. Microsoft explicitly identifies those factors in the monitoring pattern. A harmless-looking check can become a substantial workload when multiplied across many nodes and observers.

Separate lightweight readiness probes used for traffic decisions from deeper synthetic checks used for service assurance. A deeper check need not run at the same frequency as a process-level check. Record the detection delay each design can actually support.

Avoid overlapping scheduled executions where the collector cannot complete within its interval. Give the collector a bounded runtime, status output and operational owner. Keep collection and failure reporting in an owned monitoring service.

Prevent cached success from hiding failure

Inspect caching at the application, proxy and monitoring layers. A cached healthy response can outlive the condition it measured. The acceptable freshness must be part of the check contract.

ASP.NET Core’s health middleware normally sets response headers to prevent caching when its documented caching option remains at the default S2. That is useful framework behaviour, but still verify the deployed response and any intermediary rather than assuming every proxy follows the intended design.

If the architecture deliberately caches expensive health results, record the refresh interval and the resulting detection delay. A stale result should be identifiable. Do not present a cached answer as a newly completed end-to-end transaction.

Use correlation identifiers and timestamps where appropriate, while avoiding leakage of internal topology or customer data. The operator needs enough information to connect an alert to its evidence without publishing secrets through the endpoint.

Protect the monitoring surface

Health endpoints can disclose dependency names, exceptions or connection details. Microsoft recommends authentication and/or network restrictions appropriate to the monitoring service, with only the required result exposed S1. A hard-to-guess URL is not an access control.

Test that the authorised probe can reach the endpoint under normal restrictions. An interactive sign-in redirect can be mistaken for a working application page by a poorly configured monitor. Validate the expected status and response rather than accepting arbitrary HTML.

Keep detailed diagnostic output behind stronger access where possible. The routing system may need only readiness, while the incident responder needs a protected report of failed checks. Separate those needs in the design.

Do not attach automatic restarts, failover or traffic removal until the signal has been tested. Remediation changes availability and can magnify a mistaken result. The first stage should establish trustworthy observations and clear ownership.

RequireHost alone is not an access-control boundary: Microsoft warns that Host-based values can be spoofed. Its guidance includes checking HttpContext.Connection.LocalPort, host filtering and authorisation S2. Match those controls to the trusted proxy/network design; a client-supplied Host header does not authenticate the monitor.

Rehearse failures and verify the alert path

In an isolated environment, simulate a relevant dependency failure through the owner’s approved method. Confirm the intended signal changes, the monitor detects it within the measured interval and the alert reaches the responsible operational route.

Restore the dependency and verify recovery of the signal and the business operation. Include the case where the collector itself cannot reach the application. Unknown monitoring coverage must not be shown as healthy application service.

Record false positives, missed failures and untested dependencies alongside application errors and latency measurements.

Limitations

The code and behaviour claims are scoped to ASP.NET Core 8 only; no .NET 10 compatibility or lab result is claimed. The fragment needs application-owner integration and controlled failure tests. External checks establish only the paths and operations they exercise.

Acceptance checklist

  • Liveness, readiness and user-operation contracts written separately.
  • Selected checks, Degraded mapping and timeout/load limits verified.
  • Monitoring identity, uncached responses and protected endpoint access tested.
  • Representative failures produce the intended alert and recovery evidence.

Learning notes

  • A responding health endpoint may contain no dependency checks at all.
  • Liveness, readiness and useful business work require different acceptance contracts.
  • Probe cost, security, freshness and remediation are part of the design.

Related reading: IIS 502 and 503 Errors: Find the Failing Request Layer; SQL Kerberos After Migration: Check SPNs and NTLM Use; Renew IIS TLS Certificates and Verify the Live Endpoint; Scheduled Jobs After Migration: Prevent Duplicate Work.

Sources and review status

Sources accessed 30 October 2026. Exact displayed dates, scope and claim mapping are in the accompanying evidence file. Revised after independent review; independent recheck pending. All examples remain untested and no lab validation is claimed.

  1. Health Endpoint Monitoring Pattern - Azure Architecture Center | Microsoft Learn
  2. Health checks in ASP.NET Core | Microsoft Learn