Skip to content

Health Checks

Every Microtec microservice exposes standardised health check endpoints following the ASP.NET Core Health Checks framework. Container App Environments and Azure Front Door use these endpoints to determine service availability.


Endpoint Conventions

EndpointPurposeReturns
/healthAggregated health (all checks)200 Healthy / 503 Unhealthy
/health/readyReadiness — service ready to serve traffic200 Ready / 503 Not Ready
/health/liveLiveness — process is alive (not deadlocked)200 Alive / 503 Dead

Liveness vs Readiness

Liveness answers "is the process still running?". If liveness fails, the Container App runtime restarts the container.

Readiness answers "is the service ready to serve requests?". If readiness fails, the Container App runtime removes the replica from the load balancer but does NOT restart it. This is used during startup (waiting for DB connections) or during rolling restarts.

Use separate probes for each purpose. A failing DB connection should make the service not ready, but should not cause the container to restart unnecessarily.


Response Format

Health check responses follow the standard ASP.NET Core format:

Healthy (HTTP 200)

json
{
  "status": "Healthy",
  "results": {
    "database": {
      "status": "Healthy",
      "description": "SQL Server connection verified",
      "duration": "00:00:00.0124563"
    },
    "redis": {
      "status": "Healthy",
      "description": "Redis PING successful",
      "duration": "00:00:00.0031234"
    },
    "seq": {
      "status": "Healthy",
      "description": "Seq log ingestion reachable",
      "duration": "00:00:00.0089012"
    }
  }
}

Unhealthy (HTTP 503)

json
{
  "status": "Unhealthy",
  "results": {
    "database": {
      "status": "Unhealthy",
      "description": "Connection timeout after 30s",
      "exception": "Microsoft.Data.SqlClient.SqlException: ..."
    },
    "redis": {
      "status": "Healthy",
      "description": "Redis PING successful"
    }
  }
}

Implementation

Health checks are registered in the shared Microtec.Web.Core package and applied automatically to all services:

csharp
// Microtec.Web.Core / Extensions/HealthCheckExtensions.cs
public static IServiceCollection AddMicrotecHealthChecks(
    this IServiceCollection services,
    IConfiguration configuration)
{
    services.AddHealthChecks()
        .AddSqlServer(
            connectionString: configuration.GetConnectionString("DefaultConnection")!,
            name: "database",
            failureStatus: HealthStatus.Unhealthy,
            tags: ["ready"])
        .AddRedis(
            configuration["RedisConfiguration:ConnectionString"]!,
            name: "redis",
            failureStatus: HealthStatus.Degraded,
            tags: ["ready"])
        .AddUrlGroup(
            new Uri(configuration["Seq:ServerUrl"]! + "/api"),
            name: "seq",
            failureStatus: HealthStatus.Degraded,
            tags: ["ready"]);

    return services;
}

// Endpoint registration in Program.cs (via shared extension)
app.MapHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready"),
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

app.MapHealthChecks("/health/live", new HealthCheckOptions
{
    Predicate = _ => false,   // No checks — liveness is purely "process is up"
    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});

The liveness probe intentionally has Predicate = _ => false (no checks included) — it returns Healthy as long as the ASP.NET Core pipeline is processing requests, which is sufficient to confirm the process is alive.


Container App Probe Configuration

Container App probes are configured in the Bicep deployment module:

bicep
probes: [
  {
    type: 'Liveness'
    httpGet: {
      path: '/health/live'
      port: 8080
      scheme: 'HTTP'
    }
    initialDelaySeconds: 10
    periodSeconds: 30
    failureThreshold: 3
    timeoutSeconds: 5
  }
  {
    type: 'Readiness'
    httpGet: {
      path: '/health/ready'
      port: 8080
      scheme: 'HTTP'
    }
    initialDelaySeconds: 15
    periodSeconds: 10
    failureThreshold: 5
    timeoutSeconds: 10
  }
  {
    type: 'Startup'
    httpGet: {
      path: '/health/ready'
      port: 8080
      scheme: 'HTTP'
    }
    initialDelaySeconds: 5
    periodSeconds: 5
    failureThreshold: 30    // Allow up to 2.5 min for startup (EF migrations)
    timeoutSeconds: 10
  }
]

Startup Probe for EF Migrations

The startup probe with failureThreshold: 30 and periodSeconds: 5 gives services up to 150 seconds to become ready. This accommodates EF Core migration execution on first deployment of a new schema version. Without a startup probe, the liveness probe would restart the container during migration.


Azure Front Door Health Probes

AFD probes use the aggregated /health endpoint (not readiness/liveness):

PropertyValue
Path/health
ProtocolHTTPS
MethodGET
Interval30 seconds
Sample size4 samples
Successful threshold3 out of 4

AFD interprets HTTP 200 as healthy. Any other status code marks the origin as unhealthy and stops routing traffic to it.


Health Check UI

The HealthChecks.UI package runs as a sidecar dashboard on the Gateway service (dev and stage only):

EnvironmentURL
devhttps://gateway.microtec-test.com/healthchecks-ui
stagehttps://gateway.microtecstage.com/healthchecks-ui

The dashboard polls all registered services every 30 seconds and shows a colour-coded grid. It is not deployed to preprod, uat, or production to reduce attack surface.

Restrict Health Check UI Access

The healthchecks-ui endpoint is restricted to the InternalUsers IP allowlist in the Gateway Ocelot configuration. It should never be accessible without authentication in any environment above dev.


Monitoring Integration

Health check results flow into Application Insights via:

  1. AFD availability alerts — AFD health probe failures create alerts (see alerting)
  2. OpenTelemetry — Health check probe call durations are captured as spans
  3. Seq — Health check pipeline logs at Debug level in dev, Warning on unhealthy transitions in all environments

Internal Documentation — Microtec Platform Team