proactive-deps for .NET
Lightweight, cached, proactive dependency health checks for .NET services.
Define async checks (DBs, REST APIs, queues, etc.), get structured status + latency, and expose Prometheus metrics (via Prometheus.Client) out-of-the-box.
Features
- Simple registration of dependency checks
- Per-dependency TTL + refresh threshold (in-memory TTL cache with proactive refresh)
- Latency + health gauges for Prometheus (Prometheus.Client)
- Skippable checks (e.g., for local dev / disabled services)
- .NET-first API with records and async checks
Install
Until published to NuGet, add a project reference to this library:
# From your app project folder
dotnet add reference ../path/to/src/ProactiveDeps/ProactiveDeps.csproj
Or clone this repository and use the provided sample.
Quick Start
using ProactiveDeps.Monitoring;
var monitor = new DependencyMonitor(new DependencyMonitorOptions
{
// Optional defaults
CacheDurationMs = 60_000,
RefreshThresholdMs = 5_000,
CheckIntervalMs = 15_000
});
monitor.Register(new DependencyCheckOptions
{
Name = "redis",
Description = "Redis cache",
Impact = "Responses may be slower (cache miss path).",
Check = async () =>
{
// Perform your health check here (ping Redis, open DB connection, etc.)
await Task.Delay(5);
return Constants.SUCCESS_STATUS_CODE; // 0
},
// Optional per-dependency overrides
CacheDurationMs = 10_000,
RefreshThresholdMs = 5_000,
CheckDetails = new DatabaseCheckDetails("database", Server: "localhost", Database: "cache", DbType: "redis")
});
// Start periodic checks
monitor.StartDependencyCheckInterval();
// Query on-demand
var all = await monitor.GetAllStatuses();
var one = await monitor.GetStatus("redis");
// Render Prometheus text exposition
var metricsText = await monitor.GetPrometheusMetrics();
Skipping a Dependency
monitor.Register(new DependencyCheckOptions
{
Name = "external-service",
Description = "An external service that is temporarily disabled",
Impact = "No impact since this service is currently unused.",
Skip = true,
Check = async () => Constants.SUCCESS_STATUS_CODE // won't run because Skip=true
});
Return Shape
Check delegate returns either:
Constants.SUCCESS_STATUS_CODE | Constants.ERROR_STATUS_CODE | Constants.WARNING_STATUS_CODE
(int), ornew DependencyCheckResult { Code = ..., Error = ex, ErrorMessage = "..." }
Skip = true
short-circuits to an OK result with latency: 0
and skipped: true
.
Fetch All Statuses
var statuses = await monitor.GetAllStatuses();
// Example (C# record serialized to JSON):
// [
// {
// "name": "redis",
// "description": "Redis cache layer",
// "impact": "Responses may be slower due to missing cache.",
// "healthy": true,
// "health": {
// "state": "OK",
// "code": 0,
// "latency": 5,
// "skipped": false
// },
// "lastChecked": "2025-04-13T12:00:00Z"
// }
// ]
Single Dependency
var status = await monitor.GetStatus("redis");
Prometheus Metrics
The monitor initializes Prometheus.Client gauges on first use (or uses your provided registry):
dependency_latency_ms{dependency}
– last check latency (ms)dependency_health{dependency,impact}
– health state (0 OK, 1 WARNING, 2 CRITICAL)
var metrics = await monitor.GetPrometheusMetrics();
Console.WriteLine(metrics);
/*
# HELP dependency_latency_ms Last dependency check latency in milliseconds
# TYPE dependency_latency_ms gauge
dependency_latency_ms{dependency="redis"} 5
# HELP dependency_health Dependency health status (0=OK,1=WARNING,2=CRITICAL)
# TYPE dependency_health gauge
dependency_health{dependency="redis",impact="Responses may be slower (cache miss path)."} 0
*/
ASP.NET Core Integration (optional)
Use Prometheus.Client.AspNetCore
and Prometheus.Client.DependencyInjection
to expose /metrics
and share the same registry:
// Program.cs / Startup.cs
using Prometheus.Client;
using Prometheus.Client.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMetricFactory(); // adds ICollectorRegistry & IMetricFactory
var app = builder.Build();
app.UsePrometheusServer(); // exposes /metrics
// Resolve the registry/factory to pass into DependencyMonitor
var registry = app.Services.GetRequiredService<ICollectorRegistry>();
var factory = app.Services.GetRequiredService<IMetricFactory>();
var monitor = new DependencyMonitor(new DependencyMonitorOptions { CheckIntervalMs = 15000 }, registry, factory);
monitor.Register(new DependencyCheckOptions { /* ... */ });
monitor.StartDependencyCheckInterval();
app.Run();
Example Project (Console Demo)
See samples/ConsoleDemo
for a minimal runnable example.
cd samples/ConsoleDemo
dotnet run
API Documentation
For detailed API documentation, refer to the docs
License
MIT © 2025 Daniel Essig