Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 6s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 16s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 13m16s
Build ErsatzTV Image / decisions.md append-only (pull_request) Failing after 12m23s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Failing after 14m6s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m44s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 19m19s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 19m28s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
GET /api/v1/health re-ran all 14 health checks on every request, 4 of which shell out to ffmpeg/ffprobe via CliWrap — so each poll spawned ~4 subprocesses. The existing HealthCheckSummary cache was write-only. Cache the full result list for 30s inside HealthCheckService keyed on a new "healthcheck.results" entry; a non-forced call returns it on a hit, skipping the checks and the (subscriber-less) summary publish. Add a `bool forceRefresh` first parameter to IHealthCheckService.PerformHealthChecks: the API poll path reads the cache, while startup (RunHealthChecksService) and the troubleshooting support bundle force a fresh run. Refresh surface: GET /api/v1/health gains an optional `[FromQuery] bool refresh` (additive, follows the ?deep= exemplar); the SPA "Refresh health" button calls /api/v1/health?refresh=true, the initial/poll load does not. Tests: HealthCheckService cache-hit vs force-bypass (mutually opposing, non-vacuous), handler+controller refresh-flag threading, SPA refresh URL. Docs: decisions.md 2026-07-19 (#431), api-conventions §2; regenerated v1.json. fixes #431 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 lines
1.1 KiB
C#
34 lines
1.1 KiB
C#
using ErsatzTV.Core.Api.Health;
|
|
using ErsatzTV.Core.Health;
|
|
using static ErsatzTV.Application.Health.Mapper;
|
|
|
|
namespace ErsatzTV.Application.Health;
|
|
|
|
public class GetAllHealthCheckResultsForApiHandler
|
|
: IRequestHandler<GetAllHealthCheckResultsForApi, List<HealthCheckResponseModel>>
|
|
{
|
|
private readonly IHealthCheckService _healthCheckService;
|
|
|
|
public GetAllHealthCheckResultsForApiHandler(IHealthCheckService healthCheckService) =>
|
|
_healthCheckService = healthCheckService;
|
|
|
|
public async Task<List<HealthCheckResponseModel>> Handle(
|
|
GetAllHealthCheckResultsForApi request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
List<HealthCheckResult> results =
|
|
await _healthCheckService.PerformHealthChecks(request.Refresh, cancellationToken);
|
|
return results
|
|
.Filter(r => r.Status != HealthCheckStatus.NotApplicable)
|
|
.Map(ProjectToResponseModel)
|
|
.ToList();
|
|
}
|
|
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
}
|