Files
nexus/backend/Controllers/HealthController.cs
T
AzuTear cd8c78d165
CI - Build & Test / Backend (.NET) (push) Successful in 45s
CI - Build & Test / Backend integration (PostgreSQL/Toxiproxy) (push) Failing after 1m0s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 2m49s
CI - Build & Test / Security Check (push) Successful in 7s
CI - Build & Test / Deploy Nexus (push) Has been skipped
feat(stability): unify readiness and recovery
2026-08-01 01:21:33 +02:00

87 lines
2.8 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Nexus.Api.Integrations;
namespace Nexus.Api.Controllers;
[ApiController]
public class HealthController(IAgentRuntime runtime, HealthCheckService healthChecks) : ControllerBase
{
[AllowAnonymous]
[HttpGet("/health/live")]
public IResult Live()
=> Results.Ok(new
{
status = "Healthy",
timestamp = DateTimeOffset.UtcNow,
agentSource = "openclaw-rpc"
});
[AllowAnonymous]
[HttpGet("/health/ready")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
public async Task<IResult> Ready(CancellationToken ct)
{
var report = await healthChecks.CheckHealthAsync(
registration => registration.Tags.Contains("ready"),
ct);
var payload = new
{
status = report.Status == HealthStatus.Healthy ? "Healthy" : "Unhealthy",
timestamp = DateTimeOffset.UtcNow
};
return report.Status == HealthStatus.Healthy
? Results.Ok(payload)
: Results.Json(payload, statusCode: StatusCodes.Status503ServiceUnavailable);
}
[AllowAnonymous]
[HttpGet("/health")]
public async Task<IResult> Get(CancellationToken ct)
{
var report = await healthChecks.CheckHealthAsync(ct);
string runtimeStatus;
string? runtimeDetail;
try
{
var status = await runtime.GetStatusAsync(ct);
runtimeStatus = status.Status.ToString();
runtimeDetail = status.Detail;
}
catch (Exception ex)
{
runtimeStatus = "Offline";
runtimeDetail = ex.Message;
}
static IReadOnlyDictionary<string, object?> NormalizeData(IReadOnlyDictionary<string, object> source)
{
return source.ToDictionary(kvp => kvp.Key, kvp => (object?)kvp.Value);
}
var entries = report.Entries.ToDictionary(
e => e.Key,
e => new
{
status = e.Value.Status.ToString(),
description = e.Value.Description,
data = NormalizeData(e.Value.Data)
});
entries["runtime"] = new
{
status = runtimeStatus,
description = runtimeDetail,
data = new Dictionary<string, object?>() as IReadOnlyDictionary<string, object?>
};
var isHealthy = report.Status == HealthStatus.Healthy && runtimeStatus == "Online";
return isHealthy ? Results.Ok(new { status = "Healthy", checks = entries, timestamp = DateTimeOffset.UtcNow })
: Results.Ok(new { status = "Degraded", checks = entries, timestamp = DateTimeOffset.UtcNow });
}
}