113 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Diagnostics;
 | |
| using System.Text;
 | |
| using System.Text.Json;
 | |
| using Microsoft.AspNetCore.Builder;
 | |
| using Microsoft.AspNetCore.Http;
 | |
| using Microsoft.AspNetCore.Routing;
 | |
| using Microsoft.Extensions.Options;
 | |
| using StellaOps.Scanner.WebService.Diagnostics;
 | |
| using StellaOps.Scanner.WebService.Options;
 | |
| 
 | |
| namespace StellaOps.Scanner.WebService.Endpoints;
 | |
| 
 | |
| internal static class HealthEndpoints
 | |
| {
 | |
|     private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
 | |
| 
 | |
|     public static void MapHealthEndpoints(this IEndpointRouteBuilder endpoints)
 | |
|     {
 | |
|         ArgumentNullException.ThrowIfNull(endpoints);
 | |
| 
 | |
|         var group = endpoints.MapGroup("/");
 | |
|         group.MapGet("/healthz", HandleHealth)
 | |
|             .WithName("scanner.health")
 | |
|             .Produces<HealthDocument>(StatusCodes.Status200OK)
 | |
|             .AllowAnonymous();
 | |
| 
 | |
|         group.MapGet("/readyz", HandleReady)
 | |
|             .WithName("scanner.ready")
 | |
|             .Produces<ReadyDocument>(StatusCodes.Status200OK)
 | |
|             .AllowAnonymous();
 | |
|     }
 | |
| 
 | |
|     private static IResult HandleHealth(
 | |
|         ServiceStatus status,
 | |
|         IOptions<ScannerWebServiceOptions> options,
 | |
|         HttpContext context)
 | |
|     {
 | |
|         ApplyNoCache(context.Response);
 | |
| 
 | |
|         var snapshot = status.CreateSnapshot();
 | |
|         var uptimeSeconds = Math.Max((snapshot.CapturedAt - snapshot.StartedAt).TotalSeconds, 0d);
 | |
| 
 | |
|         var telemetry = new TelemetrySnapshot(
 | |
|             Enabled: options.Value.Telemetry.Enabled,
 | |
|             Logging: options.Value.Telemetry.EnableLogging,
 | |
|             Metrics: options.Value.Telemetry.EnableMetrics,
 | |
|             Tracing: options.Value.Telemetry.EnableTracing);
 | |
| 
 | |
|         var document = new HealthDocument(
 | |
|             Status: "healthy",
 | |
|             StartedAt: snapshot.StartedAt,
 | |
|             CapturedAt: snapshot.CapturedAt,
 | |
|             UptimeSeconds: uptimeSeconds,
 | |
|             Telemetry: telemetry);
 | |
| 
 | |
|         return Json(document, StatusCodes.Status200OK);
 | |
|     }
 | |
| 
 | |
|     private static async Task<IResult> HandleReady(
 | |
|         ServiceStatus status,
 | |
|         HttpContext context,
 | |
|         CancellationToken cancellationToken)
 | |
|     {
 | |
|         ApplyNoCache(context.Response);
 | |
| 
 | |
|         await Task.CompletedTask;
 | |
| 
 | |
|         status.RecordReadyCheck(success: true, latency: TimeSpan.Zero, error: null);
 | |
|         var snapshot = status.CreateSnapshot();
 | |
|         var ready = snapshot.Ready;
 | |
| 
 | |
|         var document = new ReadyDocument(
 | |
|             Status: ready.IsReady ? "ready" : "unready",
 | |
|             CheckedAt: ready.CheckedAt,
 | |
|             LatencyMs: ready.Latency?.TotalMilliseconds,
 | |
|             Error: ready.Error);
 | |
| 
 | |
|         return Json(document, StatusCodes.Status200OK);
 | |
|     }
 | |
| 
 | |
|     private static void ApplyNoCache(HttpResponse response)
 | |
|     {
 | |
|         response.Headers.CacheControl = "no-store, no-cache, max-age=0, must-revalidate";
 | |
|         response.Headers.Pragma = "no-cache";
 | |
|         response.Headers["Expires"] = "0";
 | |
|     }
 | |
| 
 | |
|     private static IResult Json<T>(T value, int statusCode)
 | |
|     {
 | |
|         var payload = JsonSerializer.Serialize(value, JsonOptions);
 | |
|         return Results.Content(payload, "application/json", Encoding.UTF8, statusCode);
 | |
|     }
 | |
| 
 | |
|     internal sealed record TelemetrySnapshot(
 | |
|         bool Enabled,
 | |
|         bool Logging,
 | |
|         bool Metrics,
 | |
|         bool Tracing);
 | |
| 
 | |
|     internal sealed record HealthDocument(
 | |
|         string Status,
 | |
|         DateTimeOffset StartedAt,
 | |
|         DateTimeOffset CapturedAt,
 | |
|         double UptimeSeconds,
 | |
|         TelemetrySnapshot Telemetry);
 | |
| 
 | |
|     internal sealed record ReadyDocument(
 | |
|         string Status,
 | |
|         DateTimeOffset CheckedAt,
 | |
|         double? LatencyMs,
 | |
|         string? Error);
 | |
| }
 |