using System.Diagnostics; using System.Diagnostics.Metrics; using Microsoft.Extensions.Options; var builder = WebApplication.CreateBuilder(args); builder.Host.UseDefaultServiceProvider(options => { options.ValidateScopes = true; options.ValidateOnBuild = true; }); builder.Services.AddOptions() .BindConfiguration("Service") .Validate(o => !string.IsNullOrWhiteSpace(o.Name), "Service name required") .ValidateOnStart(); builder.Services.AddOptions() .BindConfiguration("Dependency") .Validate(o => o.TimeoutMs > 0 && o.DelayMs >= 0, "Dependency timing invalid") .ValidateOnStart(); builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); var app = builder.Build(); // These endpoints model an explicit lesson contract; they do not probe a real dependency. app.MapGet("/live", () => Results.Ok(new { state = "alive" })); app.MapGet("/ready", (IOptions options) => options.Value.Available ? Results.StatusCode(200) : Results.StatusCode(503)); app.MapGet("/sample", async (HttpContext context, IDependency dependency, IOptions options, Telemetry telemetry, ILogger logger) => { using var operation = telemetry.Activities.StartActivity("dependency.call", ActivityKind.Internal); using var deadline = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted); deadline.CancelAfter(options.Value.TimeoutMs); try { var value = await dependency.ReadAsync(deadline.Token); return Results.Ok(new { value }); } catch (OperationCanceledException) when (!context.RequestAborted.IsCancellationRequested) { operation?.SetStatus(ActivityStatusCode.Error, "dependency_timeout"); var traceId = Activity.Current?.TraceId.ToString() ?? "unavailable"; telemetry.Timeouts.Add(1, new KeyValuePair("operation", "dependency")); logger.LogWarning(new EventId(1002, "DependencyTimeout"), "Dependency timeout. TraceId {TraceId}", traceId); // Do not return exception details, settings, headers or credentials. return Results.Json(new { error = "dependency_timeout", trace_id = traceId }, statusCode: 504); } }); app.Run(); public partial class Program { } public sealed class ServiceOptions { public string Name { get; set; } = ""; } public sealed class DependencyOptions { public int TimeoutMs { get; set; } public int DelayMs { get; set; } = 20; public bool Available { get; set; } = true; } public interface IDependency { Task ReadAsync(CancellationToken cancellationToken); } public sealed class SyntheticDependency(IOptions options) : IDependency { public async Task ReadAsync(CancellationToken cancellationToken) { await Task.Delay(options.Value.DelayMs, cancellationToken); return "synthetic-ok"; } } public sealed class Telemetry : IDisposable { public ActivitySource Activities { get; } = new("MAKNOW.Readiness"); public Meter Meter { get; } = new("MAKNOW.Readiness"); public Counter Timeouts { get; } public Telemetry() => Timeouts = Meter.CreateCounter("lesson.dependency.timeouts"); public void Dispose() { Activities.Dispose(); Meter.Dispose(); } } public sealed class LifecycleRecord { public bool Started { get; set; } public bool Stopped { get; set; } } public sealed class LifecycleProbe(LifecycleRecord record) : IHostedService { public Task StartAsync(CancellationToken token) { record.Started = true; return Task.CompletedTask; } public Task StopAsync(CancellationToken token) { record.Stopped = true; return Task.CompletedTask; } }