diff --git a/src/Budget.Api/Program.cs b/src/Budget.Api/Program.cs index 61327de..2c0dfc0 100644 --- a/src/Budget.Api/Program.cs +++ b/src/Budget.Api/Program.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; var builder = WebApplication.CreateBuilder(args); @@ -48,6 +49,32 @@ builder.Services.AddHealthChecks() var app = builder.Build(); +// Block startup until OIDC discovery succeeds (handles auth/app container race). +var jwtOpts = app.Services.GetRequiredService>() + .Get(JwtBearerDefaults.AuthenticationScheme); +var startupLogger = app.Services.GetRequiredService().CreateLogger("Startup"); +var deadline = DateTime.UtcNow + TimeSpan.FromMinutes(2); +while (true) +{ + try + { + jwtOpts.ConfigurationManager!.RequestRefresh(); + await jwtOpts.ConfigurationManager!.GetConfigurationAsync(CancellationToken.None); + startupLogger.LogInformation("OIDC discovery succeeded"); + break; + } + catch (Exception ex) + { + if (DateTime.UtcNow >= deadline) + { + startupLogger.LogWarning(ex, "OIDC discovery timed out after 2 min; continuing startup"); + break; + } + startupLogger.LogWarning(ex, "OIDC discovery failed; retrying in 5 s"); + Thread.Sleep(TimeSpan.FromSeconds(5)); + } +} + // Apply EF migrations automatically on startup using (var scope = app.Services.CreateScope()) {