Health Quickstart

Expose /healthz and aggregate basic probes (script + HTTP) into a single JSON document for liveness / readiness checks. This is the migrated version of the previous Responses chapter entry, now expanded with concepts and operational notes.

Full source

File: pwsh/tutorial/examples/16.1-Health-Quickstart.ps1

<#
    Health Quickstart Script
    Migrated from 9.11-Health-Checks.ps1
    Demonstrates basic health endpoint with script + HTTP probes.
#>
param(
    [int]$Port = 5000,
    [IPAddress]$IPAddress = [IPAddress]::Loopback
)

## 1. Logging (console sink for visibility)
New-KrLogger | Add-KrSinkConsole | Register-KrLogger -Name 'console' -SetAsDefault

## 2. Server
New-KrServer -Name 'Health Demo'

## 3. Listener (loopback port 5000)
Add-KrEndpoint -Port $Port -IPAddress $IPAddress


## 5. Enable configuration (locks in components)
Enable-KrConfiguration

## 6. Supporting route used by HTTP probe
Add-KrMapRoute -Verbs Get -Pattern '/ping' -ScriptBlock {
    Write-KrJsonResponse @{ status = 'Healthy'; description = 'Self ping successful' }
}

## 7. Health endpoint (treat degraded as unhealthy for tighter SLAs)
Add-KrHealthEndpoint -Pattern '/healthz' -DefaultTags 'self' -TreatDegradedAsUnhealthy $true -ProbeTimeout '00:00:05'

## 8. Script probe (constant healthy)
Add-KrHealthProbe -Name 'Self' -Tags 'self' -ScriptBlock {
    return New-KrProbeResult Healthy 'Main pipeline ready'
}

## 9. HTTP probe (calls /ping)
Add-KrHealthHttpProbe -Name 'Ping' -Url "http://127.0.0.1:$Port/ping" -Tags 'remote', 'self' -Timeout '00:00:02'

## 10. Start server
Start-KrServer -CloseLogsOnExit

Concepts

Term Meaning
Probe A unit of health evaluation returning Status, Description, and optional Data
Status Healthy, Degraded, or Unhealthy (optionally escalated if configured)
Endpoint Aggregator that executes selected probes in parallel and shapes the response
Tags Classification labels used to include/exclude probes per request
Timeout Per-probe timeout (endpoint-level default) after which a probe is considered failed
New-KrProbeResult Helper cmdlet simplifying creation of ProbeResult objects

Step-by-step

  1. (Logging) Configure console logger for visibility
  2. (Server) Create server & listener (loopback:5000)
  3. (Route) Map /ping returning a simple status object
  4. (Endpoint) Register /healthz with: default tag self, shorter timeout, and escalate degraded to unhealthy
  5. (Probe) Script probe Self -> static readiness confirmation
  6. (Probe) HTTP probe Ping -> validates internal route
  7. (Run) Start server; query endpoint

Response Shape

Typical aggregate (trimmed example):

{
  "status": "Healthy",
  "statusText": "healthy",
  "generatedAt": "2025-09-26T10:15:04.1234567Z",
  "summary": { "total": 2, "healthy": 2, "degraded": 0, "unhealthy": 0 },
  "appliedTags": [ "self" ],
  "probes": [
    {
      "name": "Self",
      "tags": [ "self" ],
      "status": "Healthy",
      "statusText": "healthy",
      "description": "Main pipeline ready",
      "data": null,
      "duration": "00:00:00.0001234",
      "error": null
    },
    {
      "name": "Ping",
      "tags": [ "self" ],
      "status": "Healthy",
      "statusText": "healthy",
      "description": null,
      "data": null,
      "duration": "00:00:00.0000150",
      "error": null
    }
  ]
}

Field overview:

  • status: Worst case across included probes (post escalation)
  • statusText: Lowercase string form of status (stable for consumers)
  • generatedAt: UTC timestamp when aggregation finished
  • summary: Count breakdown (total, healthy, degraded, unhealthy)
  • appliedTags: Effective tag filter used for this request
  • probes[]: Individual probe results
    • name, tags, status, statusText
    • description: Optional details
    • data: Arbitrary key/value bag (when probe returns extra context)
    • duration: Execution time (ISO 8601 hh:mm:ss.fffffff TimeSpan format)
    • error: Optional captured error text / exception summary

Execution Lifecycle

  1. Request arrives at /healthz
  2. Tag filter resolved (query: tag / tags, fallback to endpoint defaults)
  3. Probe list materialized & dispatched concurrently
  4. Each probe: run -> map result -> clamp to timeout (canceled => degraded/unhealthy per rules)
  5. Aggregate status computed (worst) then escalate if -TreatDegradedAsUnhealthy
  6. JSON serialized & returned (200 when healthy/degraded unless escalation triggers 503)

Options Summary

Option Script Param Purpose
-DefaultTags Endpoint Baseline tag set when caller omits tag(s)
-ProbeTimeout Endpoint Per-probe timeout & cancellation window
-TreatDegradedAsUnhealthy Endpoint Escalate degraded to unhealthy (for strict readiness)
-ResponseContentType Endpoint Force JSON, YAML, XML, or auto negotiation for the aggregate payload
-Tags Probe Assign classification labels
-Timeout Probe (e.g., HTTP/process) Per-probe override (stronger than endpoint default)

Filtering Examples

Query Effect
?tag=self Only self probes
?tags=remote,api remote OR api probes (union – duplicates removed)
none Default endpoint tags (self)

Multiple tag parameters are also merged: ?tag=self&tag=remote ⇒ same as ?tags=self,remote.

Failure & Escalation Scenarios

Scenario Raw Probe Status Aggregate (TreatDegradedAsUnhealthy=$true) HTTP Code
One degraded, others healthy Degraded Unhealthy 503
One unhealthy Unhealthy Unhealthy 503
All healthy Healthy Healthy 200
Timeout (internal) Degraded (mapped) Unhealthy 503

Without escalation the degraded row would remain degraded with 200.

Note: An internal probe timeout (the per-probe timer expiring) maps to Degraded first so transient slowness does not immediately fail readiness unless escalation is enabled. A caller / request cancellation (client disconnect or server shutdown token) is propagated and not converted to a probe status; the endpoint decides overall response.

Try it

Invoke-RestMethod http://127.0.0.1:5000/healthz | ConvertTo-Json -Depth 4
Invoke-RestMethod 'http://127.0.0.1:5000/healthz?tag=remote' | ConvertTo-Json -Depth 4

Custom output formats

Need a human-friendly YAML payload or legacy XML integration? Specify -ResponseContentType when registering the endpoint to override the default JSON response. Available formats:

  • Json (default) - Standard JSON format for API consumption
  • Yaml - Human-readable YAML format for debugging and configuration
  • Xml - Legacy XML format for enterprise integration
  • Auto - Content negotiation based on Accept header

The following sample demonstrates all response formats with multiple diverse probes including database connectivity simulation, cache performance monitoring, and disk space checking:

File: pwsh/tutorial/examples/16.7-Health-Response-Format.ps1

<#
    Sample:  Health Response Format
    Purpose: Shows how to configure the health endpoint to return YAML, XML, or JSON responses.
    File:    16.7-Health-Response-Format.ps1
    Notes:   Demonstrates ResponseContentType parameter options with multiple probes.
#>
param(
    [int]$Port = 5000,
    [IPAddress]$IPAddress = [IPAddress]::Loopback
)

## 1. Logging
New-KrLogger | Add-KrSinkConsole | Register-KrLogger -Name 'console' -SetAsDefault

## 2. Server
New-KrServer -Name 'Health Response Format Demo'

## 3. Listener (port 5000)
Add-KrEndpoint -Port $Port -IPAddress $IPAddress

#
## 5. Add some diverse probes for demonstration
Add-KrHealthProbe -Name 'Database' -Tags 'core', 'data' -ScriptBlock {
    # Simulate database connectivity check
    $connectionTime = Get-Random -Minimum 10 -Maximum 50
    $data = @{ connectionTimeMs = $connectionTime; server = 'localhost:5432' }
    New-KrProbeResult 'Healthy' "Connected in ${connectionTime}ms" -Data $data
}

Add-KrHealthProbe -Name 'Cache' -Tags 'core', 'perf' -ScriptBlock {
    # Simulate cache health check
    $hitRatio = [math]::Round((Get-Random -Minimum 85 -Maximum 98) / 100.0, 2)
    $data = @{ hitRatio = $hitRatio; entries = 1247 }
    $status = if ($hitRatio -lt 0.8) { 'Degraded' } else { 'Healthy' }
    New-KrProbeResult $status "Hit ratio: $($hitRatio * 100)%" -Data $data
}

Add-KrHealthProbe -Name 'Disk Space' -Tags 'infra' -ScriptBlock {
    # Simulate disk space check
    $freePercent = Get-Random -Minimum 25 -Maximum 85
    $status = if ($freePercent -lt 10) { 'Unhealthy' } elseif ($freePercent -lt 20) { 'Degraded' } else { 'Healthy' }
    $data = @{ freePercent = $freePercent; totalGB = 500; freeGB = [math]::Round($freePercent * 5, 1) }
    New-KrProbeResult $status "Free space: $freePercent%" -Data $data
}

## 6. Enable configuration
#Enable-KrConfiguration

## 7. Health endpoint with different response formats (uncomment one at a time to test)
# JSON (default)
Add-KrHealthEndpoint -Pattern '/healthz' -DefaultTags 'core' -ResponseContentType Auto
Enable-KrConfiguration
## 8. Start server
Start-KrServer

This example creates three endpoints:

  • /healthz - Returns YAML format using -ResponseContentType Yaml
  • /health-json - Manual JSON endpoint using WriteJsonResponse
  • /health-xml - Manual XML endpoint using WriteXmlResponse

The probes demonstrate different health scenarios with realistic data and status mapping:

  • Database probe - Simulates connection timing with random latency
  • Cache probe - Monitors hit ratio with degraded threshold at 80%
  • Disk Space probe - Checks free space with unhealthy <10%, degraded <20%

Troubleshooting

Symptom Likely Cause Resolution
Endpoint slow (>1s) Too many long probes running in parallel Shorten probe timeout; split into readiness vs diagnostics endpoint
Random degraded spikes Intermittent dependency latency Add retry inside probe or widen degraded threshold
503 on deployment start Strict escalation Temporarily disable -TreatDegradedAsUnhealthy during warm-up
Missing probe in output Tag filtering excluded it Check query tags & default tags

References


Previous / Next

Previous: None Next: Script Probe