Skip to content
Healthie.NET
Live, not a screenshotOpen source · MIT · .NET 8 & .NET 10

Health checks that keep running when nobody is asking.

/health tells you the truth at the moment you call it. Healthie.NET runs each check on its own interval, escalates only once failures repeat, and keeps the history — so you find out on the third timeout rather than on the first support ticket.

dotnet add package Healthie.NET
See it running
Unhealthythreshold cleared, escalatedconsecutive failures 4/2
Healthie1 failing
  • Checkout API

    200 OK · p95 64ms

  • Primary Database

    SELECT 1 · 3ms

  • Payments Gateway

    Gateway timeout after 5s · 3 in a row

  • Order Worker

    Queue drained · 0 pending

  • Edge Cache

    Hit rate 92%

  • TLS Certificate

    Valid · expires in 54 days

read-only · the full board is further down

Version
4.1.0
Targets
net8.0 · net10.0
Licence
MIT
Packages
0
Deps in core
0

Same input · two readings

One dropped connection and a real outage are the same event, until something counts them.

Both lanes below are reading the identical sequence of check results. The only difference is whether a failure has to repeat before it is allowed to mean anything.

Pass / faildecided on the spot
Counted firstunhealthyThreshold: 2

Two lanes read the same sequence of health check results. Read as pass or fail, three separate failures each register as an outage. Read with a consecutive-failure threshold of 2, the single failure and the pair are held as Suspicious, and only the run of four escalates to Unhealthy.

Three failures above, one outage below. The threshold is a constructor argument per checker, so the flaky third-party API and the database do not have to share your patience.

The exact rule →

The three-state model

Two states cannot tell a blip from an outage.

Up-or-down means a single dropped connection looks exactly like a dead database. Healthie.NET adds a state in between and a count of how many failures in a row it has seen, so escalation is a property of the check rather than a rule you rewrite in every alerting tool.

Healthy

The check passed.

consecutiveFailures resets to 0 on every pass, so recovery is immediate and total.

Suspicious

It failed, but not often enough yet.

A failure at or below the threshold is held here rather than promoted. One timeout is weather, not climate.

Unhealthy

It has failed past its threshold.

Now it counts. The threshold is per checker, so a flaky API and a database can hold different patience.

The transition rule, on every tick
failed        → consecutiveFailures += 1
passed        → consecutiveFailures  = 0

failed and consecutiveFailures > threshold
              → promote to Unhealthy

unhealthy and consecutiveFailures ≤ threshold
              → demote to  Suspicious

The threshold is a constructor argument on each checker, so a third-party API you expect to wobble and a database you do not can hold different patience without a rule living anywhere else.

The default is 0. At zero the comparison is > 0, so the first failure escalates immediately and the three-state model stays out of your way until you ask for it.

A failure to reach the state store is not a failed check — it throws rather than recording a result, because writing "unhealthy" when the storage is down would report a healthy component as broken.


Live · not a screenshot

This is the dashboard, running, right now.

Read-only, so nothing on it can be changed from here. It is watching the real status endpoints of services you probably depend on — when one of them has a bad afternoon, you will see it here before you see it anywhere else on this page.

  • Anthropic
  • OpenAI
  • Cursor
  • GitHub
  • Cloudflare
  • npm
  • Datadog
  • · and more, on their real status pages
board.healthie-dotnet.devOpen in a tab
Skip the live dashboard

Built from the published NuGet packages at version 4.1.0, not from a local checkout — if the packages on nuget.org were broken, this board would be broken too. State is in-memory, so it resets whenever the demo redeploys.

Nothing above? Open the board directly — some networks and privacy extensions block embedded frames.

Read the source

Writing one

A checker is a class with one method.

Return a state and a message. The interval, the failure threshold, the group and the tags are constructor arguments and properties, so the schedule lives next to the check rather than in configuration somewhere else.

DatabaseChecker.cs
public sealed class DatabaseChecker(IStateProvider state)
    : PulseChecker(
        state,
        PulseInterval.Every30Seconds,
        unhealthyThreshold: 2)
{
    public override string DisplayName => "Primary Database";
    public override string? DefaultGroup => "Data";
    public override IReadOnlyList<string> DefaultTags =>
        ["tier-1", "sql"];

    public override async Task<PulseCheckerResult> CheckAsync(
        CancellationToken ct = default)
    {
        await using var connection =
            new SqlConnection(_connectionString);
        await connection.OpenAsync(ct);

        return new PulseCheckerResult(
            PulseCheckerHealth.Healthy,
            "SELECT 1 responded");
    }
}
Program.cs
// Finds every pulse checker and starts
// monitoring on the intervals they declare.
// No scheduler to configure, no storage
// to stand up.
builder.Services
    .AddHealthie(typeof(Program).Assembly);

// The dashboard, served at /healthie/dashboard
builder.Services.AddHealthieUI();
app.MapHealthieUI();

Assembly scanning registers every PulseChecker it finds as a singleton. There is no list to keep in step, and nothing else to wire — the in-memory state provider and the timer scheduler are registered by default, so this runs standalone before you have chosen anything.

Or write none of it

The checks you already have, on a schedule, with history.

Every registered IHealthCheck — yours, or the community ones for SQL Server, Redis, RabbitMQ, Azure or AWS — becomes a pulse checker with intervals and thresholds. Nothing is rewritten and nothing is replaced.

The whole migration
builder.Services
    .AddHealthie(typeof(Program).Assembly)
    .AddHealthieForHealthChecks();

What it does

Everything heavy is opt-in.

One package gets you running. A provider, a scheduler, the dashboard or the REST API is a separate install, and each exists to keep its driver off machines that do not need it. Each tile below names the package the claim lives in.

The one most people miss

It doesn't replace your health checks. It schedules them.

Already have IHealthCheck implementations — yours, or the community ones for SQL Server, Redis, RabbitMQ, Azure or AWS? One call gives every one of them intervals, thresholds and history, with nothing rewritten.

One wrinkle worth knowing: HealthStatus.Degraded maps to Suspicious, but the two do not mean quite the same thing — Degraded is impaired but working, Suspicious is a failure not yet confirmed by repetition. At the default threshold of 0 a degraded check therefore reports Unhealthy on its first failure. Give it a threshold of at least 1.

Adopting what you already have
builder.Services.AddHealthChecks()
    .AddSqlServer(connectionString, name: "orders-db")
    .AddRedis(redisConnectionString, name: "cache");

builder.Services.AddHealthie();

// Schedules every health check above, with a
// threshold, history, and the dashboard.
builder.Services.AddHealthieForHealthChecks(
    PulseInterval.Every30Seconds,
    unhealthyThreshold: 2);

in Healthie.NET · call it after your AddHealthChecks() registrations

It tells someone

Alerts on a change, not on every check.

Slack, Teams, PagerDuty, a webhook, or your own sink. Recovery notices and flap suppression included — and a webhook that is down cannot delay a check or make a healthy component look unhealthy.

Healthie.NET.Alerting

It reports on itself

A Meter and an ActivitySource OpenTelemetry finds by name.

Those two need no package at all. Uptime over an arbitrary window — which a hundred-entry history cannot answer — is one more.

AddHealthieUptime();

Healthie.NET.Uptime

It scales out

Three replicas, one set of checks.

Leader election runs the checks on one replica at a time, so three instances do not check everything three times.

AddHealthieLeaderElection();

Healthie.NET.LeaderElection

Nothing to stand up

It runs before you configure anything.

A PeriodicTimer scheduler and an in-memory store are registered by default. Swap in Quartz or Postgres when you outgrow them; your checker code does not change.

in Healthie.NET

Built for agents

An MCP server that is read-only until you say otherwise.

So an agent can read health and act on it only if you let it. Kubernetes liveness and readiness probes come with the REST API, and the dashboard has no third-party dependencies and no web fonts, so it runs air-gapped.

Healthie.NET.Mcp · .Api · .Dashboard


The ecosystem

One package to install.20 more only if you want them.

Healthie.NET is not a bundle — it depends on one package and nothing else, so no database driver, scheduler or UI framework lands on your machine unless you name it. Everything below is a decision you get to defer.

Swap the storage

6

State is written every tick. In-memory loses it on restart; these do not. Separate because each carries a database driver.

  • Healthie.NET.Postgres

    PostgreSQL, including Databricks Lakebase

  • Healthie.NET.SqlServer

    SQL Server and Azure SQL

  • Healthie.NET.Sqlite

    Durable, with no server to stand up

  • Healthie.NET.CosmosDb

    Azure CosmosDB

  • Healthie.NET.Redis

    The fastest, for state written every tick

  • Healthie.NET.Relational

    The engine behind the three SQL providers. Point it at any ADO.NET database

Swap the scheduler

4

The built-in timer schedules in-process and forgets on restart, which is right for most apps. These put the schedule somewhere that outlives it.

  • Healthie.NET.Quartz

    Quartz.NET, if you already run it

  • Healthie.NET.Hangfire

    Schedules survive a restart; each occurrence runs on one replica

  • Healthie.NET.Coravel

    Coravel, if you already run it

  • Healthie.NET.Temporal

    Schedules live in the cluster

Add a surface

3

Somewhere to look, or something to call.

  • Healthie.NET.Dashboard

    The Blazor dashboard. Zero third-party dependencies, no web fonts, runs air-gapped

  • Healthie.NET.Api

    REST endpoints for managing checkers, plus liveness and readiness probes

  • Healthie.NET.Mcp

    A Model Context Protocol server, so an agent can read and act on health

Add a capability

5

Alerting, ready-made checkers, uptime, AI — and the one that stops three replicas doing the same work three times.

  • Healthie.NET.Alerting

    Health changes become alerts — Slack, Teams, PagerDuty, a webhook, or your own sink

  • Healthie.NET.Checkers

    HTTP endpoints, TCP ports, TLS expiry, DNS and disk space, with no checker code to write

  • Healthie.NET.Uptime

    Uptime and SLA over any window, by recording transitions rather than every check

  • Healthie.NET.LeaderElection

    Runs the checks on one replica at a time, so a scaled-out app checks each component once

  • Healthie.NET.AI

    Explains a checker's recent failures through any IChatClient

Reference it directly

2

For library authors shipping a provider of their own.

  • Healthie.NET.Abstractions

    The contracts and PulseChecker, with exactly one dependency

  • Healthie.NET.DependencyInjection

    What Healthie.NET resolves to. Reference it directly if you would rather be explicit

One version, all of it

Every package in this list is published at the same version, together.

There is no matrix to reason about and no provider trailing two minors behind the core it plugs into. Upgrading is one number.

current · 4.1.0

Trust your uptime

It runs standalone before you configure anything.

Add the package, write one class, and there is a dashboard. Everything after that — a provider, a scheduler, alerting, the REST API — is a decision you get to defer.

dotnet add package Healthie.NET
No database
an in-memory store is registered by default
No scheduler
a PeriodicTimer runs the intervals your checkers declare
No service
nothing to sign up for, nothing phoning home