Conversation
Teaches ASP.NET Core health check configuration for Kubernetes: liveness vs readiness vs startup probes, custom health checks for dependencies (SQL, Redis, external APIs), and K8s YAML configuration. Eval results: +33.1% improvement over baseline (threshold: 10%) Includes eval.yaml with K8s probe scenario + negative test.
There was a problem hiding this comment.
Pull request overview
This pull request adds a new implementing-health-checks skill that teaches ASP.NET Core health check configuration for Kubernetes deployments, with a reported +33.1% improvement in evaluation metrics.
Changes:
- Adds comprehensive skill documentation covering liveness, readiness, and startup probes with proper separation of concerns
- Includes code examples for health check registration, custom health checks, response formatters, and Kubernetes probe configuration
- Provides eval.yaml tests with positive scenario (Kubernetes health checks) and negative scenario (ensuring skill doesn't activate for APM/monitoring requests)
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/dotnet/skills/implementing-health-checks/SKILL.md | Complete skill documentation with workflow steps, code examples, Kubernetes YAML configuration, and common pitfalls table |
| src/dotnet/tests/implementing-health-checks/eval.yaml | Test scenarios validating proper liveness/readiness separation and skill activation boundaries |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Startup: Kubernetes startupProbe hits this | ||
| app.MapHealthChecks("/healthz/startup", new HealthCheckOptions | ||
| { | ||
| Predicate = _ => true, |
There was a problem hiding this comment.
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"), |
| 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" }); |
There was a problem hiding this comment.
The Common Pitfalls section recommends adding timeout parameters to health check registrations, but the example code in Step 2 doesn't include any timeout parameters. For consistency and to demonstrate best practices, consider adding timeout parameters to the health check registrations in Step 2. For example: .AddSqlServer(connectionString: ..., name: "database", tags: new[] { "ready" }, timeout: TimeSpan.FromSeconds(5))
| 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)); |
| ### Step 1: Add the health checks packages | ||
|
|
||
| ```bash | ||
| dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks |
There was a problem hiding this comment.
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.
| dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks |
Skill Validation Results — implementing-health-checks
Overall improvement: +17.2% (3 runs, not statistically significant) Model: claude-opus-4.6 | Judge: claude-opus-4.6 |
1 similar comment
Skill Validation Results — implementing-health-checks
Overall improvement: +17.2% (3 runs, not statistically significant) Model: claude-opus-4.6 | Judge: claude-opus-4.6 |
|
Superseded by #263 which uses the new plugins/ directory structure and addresses review feedback. |
Summary
Adds the implementing-health-checks skill that teaches ASP.NET Core health check configuration for Kubernetes deployments.
Eval Results
Overall improvement: +17.2% (3 runs)
Model: claude-opus-4.6 | Judge: claude-opus-4.6
What the Skill Teaches
Why This Skill Passes
The model confuses liveness and readiness probe semantics (putting dependency checks on liveness causes unnecessary pod restarts). This skill teaches the correct probe-to-check mapping and the specific K8s YAML configuration.
Files