-
Notifications
You must be signed in to change notification settings - Fork 369
Add implementing-health-checks skill #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,169 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||
| name: implementing-health-checks | ||||||||||||||||||||||||||||||||||||||||||||
| description: Implement ASP.NET Core health checks with liveness, readiness, and startup probes for Kubernetes and load balancer integration. Use when configuring health endpoints, monitoring dependencies, or setting up container orchestration probes. | ||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| # Implementing Health Checks | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ## When to Use | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - Adding health check endpoints to an ASP.NET Core app | ||||||||||||||||||||||||||||||||||||||||||||
| - Configuring Kubernetes liveness, readiness, and startup probes | ||||||||||||||||||||||||||||||||||||||||||||
| - Monitoring database, cache, or external service availability | ||||||||||||||||||||||||||||||||||||||||||||
| - Load balancer health endpoint configuration | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ## When Not to Use | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - The app is not ASP.NET Core | ||||||||||||||||||||||||||||||||||||||||||||
| - The user wants application performance monitoring (use OpenTelemetry instead) | ||||||||||||||||||||||||||||||||||||||||||||
| - The user needs business-level monitoring (use custom metrics) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ## Inputs | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| | Input | Required | Description | | ||||||||||||||||||||||||||||||||||||||||||||
| |-------|----------|-------------| | ||||||||||||||||||||||||||||||||||||||||||||
| | ASP.NET Core project | Yes | The project to add health checks to | | ||||||||||||||||||||||||||||||||||||||||||||
| | Dependencies to monitor | No | Database, Redis, message queue, etc. | | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ## Workflow | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ### Step 1: Add the health checks packages | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||||||||||||||||||||
| dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks | ||||||||||||||||||||||||||||||||||||||||||||
| dotnet add package AspNetCore.HealthChecks.SqlServer # for SQL Server | ||||||||||||||||||||||||||||||||||||||||||||
| dotnet add package AspNetCore.HealthChecks.Redis # for Redis | ||||||||||||||||||||||||||||||||||||||||||||
| dotnet add package AspNetCore.HealthChecks.Uris # for HTTP dependencies | ||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ### Step 2: Register health checks with SEPARATE liveness and readiness | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| **Critical distinction** most implementations get wrong: | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| - **Liveness** = "Is the process alive?" — Only checks the process isn't deadlocked. Failure → Kubernetes RESTARTS the pod. | ||||||||||||||||||||||||||||||||||||||||||||
| - **Readiness** = "Can the process serve traffic?" — Checks dependencies. Failure → Kubernetes STOPS SENDING traffic (but doesn't restart). | ||||||||||||||||||||||||||||||||||||||||||||
| - **Startup** = "Has the initial startup completed?" — One-time check. Failure during grace period is expected. | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| ```csharp | ||||||||||||||||||||||||||||||||||||||||||||
| builder.Services.AddHealthChecks() | ||||||||||||||||||||||||||||||||||||||||||||
| // Liveness checks: ONLY check the process itself, NEVER external dependencies | ||||||||||||||||||||||||||||||||||||||||||||
| .AddCheck("self", () => HealthCheckResult.Healthy(), tags: new[] { "live" }) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // Readiness checks: check external dependencies | ||||||||||||||||||||||||||||||||||||||||||||
| .AddSqlServer( | ||||||||||||||||||||||||||||||||||||||||||||
| connectionString: builder.Configuration.GetConnectionString("Default")!, | ||||||||||||||||||||||||||||||||||||||||||||
| name: "database", | ||||||||||||||||||||||||||||||||||||||||||||
| tags: new[] { "ready" }) | ||||||||||||||||||||||||||||||||||||||||||||
| .AddRedis( | ||||||||||||||||||||||||||||||||||||||||||||
| redisConnectionString: builder.Configuration.GetConnectionString("Redis")!, | ||||||||||||||||||||||||||||||||||||||||||||
| name: "redis", | ||||||||||||||||||||||||||||||||||||||||||||
| tags: new[] { "ready" }) | ||||||||||||||||||||||||||||||||||||||||||||
| .AddUrlGroup( | ||||||||||||||||||||||||||||||||||||||||||||
| new Uri("https://api.external-service.com/health"), | ||||||||||||||||||||||||||||||||||||||||||||
| name: "external-api", | ||||||||||||||||||||||||||||||||||||||||||||
| tags: new[] { "ready" }); | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+56
to
+64
|
||||||||||||||||||||||||||||||||||||||||||||
| tags: new[] { "ready" }) | |
| .AddRedis( | |
| redisConnectionString: builder.Configuration.GetConnectionString("Redis")!, | |
| name: "redis", | |
| tags: new[] { "ready" }) | |
| .AddUrlGroup( | |
| new Uri("https://api.external-service.com/health"), | |
| name: "external-api", | |
| tags: new[] { "ready" }); | |
| tags: new[] { "ready" }, | |
| timeout: TimeSpan.FromSeconds(5)) | |
| .AddRedis( | |
| redisConnectionString: builder.Configuration.GetConnectionString("Redis")!, | |
| name: "redis", | |
| tags: new[] { "ready" }, | |
| timeout: TimeSpan.FromSeconds(5)) | |
| .AddUrlGroup( | |
| new Uri("https://api.external-service.com/health"), | |
| name: "external-api", | |
| tags: new[] { "ready" }, | |
| timeout: TimeSpan.FromSeconds(5)); |
Copilot
AI
Feb 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The startup probe configuration uses Predicate = _ => true, which executes ALL registered health checks including database, Redis, and external API dependency checks. This contradicts Kubernetes best practices: startup probes should check the same thing as liveness probes (process health only), not readiness checks (dependencies). The current implementation means if any dependency is unavailable during the 150-second startup window, Kubernetes will kill the pod rather than marking it as "not ready". Consider changing to Predicate = check => check.Tags.Contains("live") to align with the liveness/readiness separation pattern explained in Step 2.
| Predicate = _ => true, | |
| Predicate = check => check.Tags.Contains("live"), |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| scenarios: | ||
| - name: "Add health checks with Kubernetes probes" | ||
| prompt: "I need to add health checks to my ASP.NET Core API for Kubernetes deployment. It should check the database and Redis connections and have separate liveness and readiness endpoints." | ||
| assertions: | ||
| - type: "output_matches" | ||
| pattern: "(AddHealthChecks|MapHealthChecks)" | ||
| - type: "output_matches" | ||
| pattern: "(liveness|readiness|live|ready)" | ||
| - type: "output_matches" | ||
| pattern: "(healthz|health)" | ||
| rubric: | ||
| - "Separated liveness and readiness health checks using tags" | ||
| - "Liveness probe does NOT check external dependencies (database, Redis) — only process health" | ||
| - "Readiness probe checks database and Redis connectivity" | ||
| - "Mapped separate endpoints for liveness and readiness (e.g., /healthz/live and /healthz/ready)" | ||
| - "Explained WHY liveness should not check dependencies (restart cascading)" | ||
| - "Provided Kubernetes probe YAML configuration or explained probe settings" | ||
| expect_tools: ["bash"] | ||
| timeout: 120 | ||
|
|
||
| - name: "Health check skill should not activate for monitoring setup" | ||
| prompt: "I want to add application performance monitoring with OpenTelemetry to track request latency and error rates." | ||
| assertions: | ||
| - type: "output_not_contains" | ||
| value: "AddHealthChecks" | ||
| - type: "output_not_contains" | ||
| value: "MapHealthChecks" | ||
| rubric: | ||
| - "Did NOT suggest health checks for an APM/observability request" | ||
| - "Focused on OpenTelemetry setup (tracing, metrics, exporters)" | ||
| timeout: 60 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package Microsoft.Extensions.Diagnostics.HealthChecks is already included in ASP.NET Core framework references and doesn't need to be explicitly installed. While this line isn't harmful, it's redundant and could be removed to avoid confusion.