food-market/src/food-market.api/Infrastructure/Health/DatabaseReadyHealthCheck.cs
nns 82bf53bb5c feat(api): health-пробы /health/live и /health/ready (P0-4)
/health/live — liveness без зависимостей (Predicate=false).
/health/ready — readiness: DatabaseReadyHealthCheck (CanConnect + нет
неприменённых миграций), тег ready, 503 если не готово. JSON-ответ по
каждому чеку. docker-compose api healthcheck + Dockerfile.api → /health/ready,
web ждёт api service_healthy. /health сохранён для обратной совместимости.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 02:23:48 +05:00

44 lines
2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using foodmarket.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Diagnostics.HealthChecks;
namespace foodmarket.Api.Infrastructure.Health;
/// <summary>Readiness-проба: приложение готово принимать трафик только когда
/// БД отвечает И все миграции применены. Если есть неприменённые миграции —
/// схема не соответствует коду (например, контейнер поднялся раньше, чем
/// отработал <c>Migrate()</c>, или откатили не ту версию) — отдаём Unhealthy,
/// чтобы оркестратор/прокси не слал на этот инстанс запросы.</summary>
public sealed class DatabaseReadyHealthCheck : IHealthCheck
{
private readonly AppDbContext _db;
public DatabaseReadyHealthCheck(AppDbContext db) => _db = db;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
if (!await _db.Database.CanConnectAsync(cancellationToken))
{
return HealthCheckResult.Unhealthy("Нет соединения с БД.");
}
var pending = (await _db.Database.GetPendingMigrationsAsync(cancellationToken)).ToList();
if (pending.Count > 0)
{
return HealthCheckResult.Unhealthy(
$"Неприменённые миграции: {pending.Count} (первая: {pending[0]}).",
data: new Dictionary<string, object> { ["pendingMigrations"] = pending });
}
return HealthCheckResult.Healthy("БД доступна, миграции применены.");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("Ошибка проверки готовности БД.", ex);
}
}
}