From 1317e97aa3fbc87ceb2e96e936e452d4d78e9530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Wed, 18 Sep 2024 23:55:40 +0200 Subject: [PATCH 01/49] sup --- ...igdir.Domain.Dialogporten.Infrastructure.csproj | 4 ++++ .../InfrastructureExtensions.cs | 14 ++++++++++++++ src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 8 +++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj index 929f0dc6e..6bc46d33f 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj @@ -1,12 +1,16 @@  + + + + diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 0b40eff71..19316d8e7 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -30,6 +30,7 @@ using Digdir.Domain.Dialogporten.Infrastructure.Persistence.Configurations.Actors; using Digdir.Domain.Dialogporten.Infrastructure.Persistence.Repositories; using HotChocolate.Subscriptions; +using Microsoft.Extensions.Diagnostics.HealthChecks; using StackExchange.Redis; using ZiggyCreatures.Caching.Fusion; using ZiggyCreatures.Caching.Fusion.NullObjects; @@ -182,6 +183,19 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi }) .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); + services.AddHealthChecks() + .AddRedis( + redisConnectionString: infrastructureSettings.Redis.ConnectionString, + name: "Redis", + failureStatus: HealthStatus.Unhealthy, + tags: ["redis"]) + .AddNpgSql( + connectionString: infrastructureSettings.DialogDbConnectionString, + name: "postgres", + healthQuery: "SELECT 1", + failureStatus: HealthStatus.Unhealthy, + tags: ["db", "postgres"]); + if (environment.IsDevelopment()) { var localDeveloperSettings = configuration.GetLocalDevelopmentSettings(); diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 0ff2a5188..e278cc59a 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -19,8 +19,10 @@ using FastEndpoints; using FastEndpoints.Swagger; using FluentValidation; +using HealthChecks.UI.Client; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using NSwag; using Serilog; @@ -200,7 +202,11 @@ static void BuildAndRun(string[] args) uiConfig.DocumentPath = dialogPrefix + "/swagger/{documentName}/swagger.json"; }); app.MapControllers(); - app.MapHealthChecks("/healthz"); + app.MapHealthChecks("/healthz", new HealthCheckOptions + { + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.Run(); } From 51c3515b9d1e1849cea2d9893112c1e64a2c75ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Thu, 19 Sep 2024 00:08:37 +0200 Subject: [PATCH 02/49] low cse --- .../InfrastructureExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 19316d8e7..57e8d24c8 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -186,7 +186,7 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi services.AddHealthChecks() .AddRedis( redisConnectionString: infrastructureSettings.Redis.ConnectionString, - name: "Redis", + name: "redis", failureStatus: HealthStatus.Unhealthy, tags: ["redis"]) .AddNpgSql( From b25034ea54e1e8110a7cbc20d39435e6824201d8 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 18:43:22 +0200 Subject: [PATCH 03/49] chore: mo health checks pls --- .../InfrastructureExtensions.cs | 4 +-- .../Program.cs | 27 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 57e8d24c8..45016fb7c 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -188,13 +188,13 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi redisConnectionString: infrastructureSettings.Redis.ConnectionString, name: "redis", failureStatus: HealthStatus.Unhealthy, - tags: ["redis"]) + tags: ["dependencies", "redis"]) .AddNpgSql( connectionString: infrastructureSettings.DialogDbConnectionString, name: "postgres", healthQuery: "SELECT 1", failureStatus: HealthStatus.Unhealthy, - tags: ["db", "postgres"]); + tags: ["dependencies", "db", "postgres"]); if (environment.IsDevelopment()) { diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index e278cc59a..ab2208b6e 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -23,6 +23,7 @@ using Microsoft.ApplicationInsights.Extensibility; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.Diagnostics.HealthChecks; using NSwag; using Serilog; @@ -125,14 +126,14 @@ static void BuildAndRun(string[] args) }; }) .AddControllers(options => options.InputFormatters.Insert(0, JsonPatchInputFormatter.Get())) - .AddNewtonsoftJson() - .Services - + .AddNewtonsoftJson() + .Services // Auth .AddDialogportenAuthentication(builder.Configuration) .AddAuthorization() - .AddHealthChecks(); + .AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]); if (builder.Environment.IsDevelopment()) { @@ -202,8 +203,24 @@ static void BuildAndRun(string[] args) uiConfig.DocumentPath = dialogPrefix + "/swagger/{documentName}/swagger.json"; }); app.MapControllers(); - app.MapHealthChecks("/healthz", new HealthCheckOptions + app.MapHealthChecks("/startup", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("dependencies"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("self"), // Retains the self check for liveness + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.MapHealthChecks("/readiness", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("dependencies"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.MapHealthChecks("/health", new HealthCheckOptions { + Predicate = check => check.Tags.Contains("dependencies"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); From 42326d104a6bf3236c11972f34c535c342eafd65 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 19:00:01 +0200 Subject: [PATCH 04/49] chore: even mo health checks pls --- .../HealthChecks/WellKnownHealthChecks.cs | 58 +++++++++++++++++++ .../InfrastructureExtensions.cs | 13 ++++- 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs new file mode 100644 index 000000000..518f24315 --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -0,0 +1,58 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; + +public class WellKnownEndpointsHealthCheck : IHealthCheck +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly ILogger _logger; + private readonly IConfiguration _configuration; + + public WellKnownEndpointsHealthCheck( + IHttpClientFactory httpClientFactory, + ILogger logger, + IConfiguration configuration) + { + _httpClientFactory = httpClientFactory; + _logger = logger; + _configuration = configuration; + } + + public async Task CheckHealthAsync( + HealthCheckContext context, + CancellationToken cancellationToken = default) + { + var wellKnownEndpoints = _configuration.GetSection("WebApi:Authentication:JwtBearerTokenSchemas") + .GetChildren() + .Select(section => section.GetValue("WellKnown")) + .ToList(); + + var client = _httpClientFactory.CreateClient("HealthCheckClient"); + + foreach (var url in wellKnownEndpoints) + { + try + { + var response = await client.GetAsync(url, cancellationToken); + if (!response.IsSuccessStatusCode) + { + _logger.LogWarning("Health check failed for Well-Known endpoint: {Url}", url); + return HealthCheckResult.Unhealthy($"Well-Known endpoint {url} is unhealthy."); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occurred while checking Well-Known endpoint: {Url}", url); + return HealthCheckResult.Unhealthy($"Exception occurred while checking Well-Known endpoint {url}."); + } + } + + return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); + } +} diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 45016fb7c..9103836ea 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -34,6 +34,7 @@ using StackExchange.Redis; using ZiggyCreatures.Caching.Fusion; using ZiggyCreatures.Caching.Fusion.NullObjects; +using Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; namespace Digdir.Domain.Dialogporten.Infrastructure; @@ -183,18 +184,26 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi }) .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); + services.AddHttpClient("HealthCheckClient") + .SetHandlerLifetime(TimeSpan.FromSeconds(10)); + services.AddHealthChecks() .AddRedis( redisConnectionString: infrastructureSettings.Redis.ConnectionString, name: "redis", failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies", "redis"]) + tags: ["dependencies"]) .AddNpgSql( connectionString: infrastructureSettings.DialogDbConnectionString, name: "postgres", healthQuery: "SELECT 1", failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies", "db", "postgres"]); + tags: ["dependencies"]) + .AddCheck( + "Well-Known Endpoints", + failureStatus: HealthStatus.Unhealthy, + tags: ["dependencies", "auth"]); + if (environment.IsDevelopment()) { From ddf0ce791ea660b469150e64d2b6d4fc6b0aa7e8 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 19:17:12 +0200 Subject: [PATCH 05/49] cleanup --- .../HealthChecks/WellKnownHealthChecks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs index 518f24315..dcd892181 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -8,7 +8,7 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; -public class WellKnownEndpointsHealthCheck : IHealthCheck +internal sealed class WellKnownEndpointsHealthCheck : IHealthCheck { private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger _logger; From d58b8e4fb0e06dfd3a4e4f8f47c316761ead20f0 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 19:19:11 +0200 Subject: [PATCH 06/49] Update src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../HealthChecks/WellKnownHealthChecks.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs index dcd892181..a329432aa 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -35,6 +35,8 @@ public async Task CheckHealthAsync( var client = _httpClientFactory.CreateClient("HealthCheckClient"); + var unhealthyEndpoints = new List(); + foreach (var url in wellKnownEndpoints) { try @@ -42,17 +44,25 @@ public async Task CheckHealthAsync( var response = await client.GetAsync(url, cancellationToken); if (!response.IsSuccessStatusCode) { - _logger.LogWarning("Health check failed for Well-Known endpoint: {Url}", url); - return HealthCheckResult.Unhealthy($"Well-Known endpoint {url} is unhealthy."); + _logger.LogWarning("Health check failed for Well-Known endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); + unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } } catch (Exception ex) { _logger.LogError(ex, "Exception occurred while checking Well-Known endpoint: {Url}", url); - return HealthCheckResult.Unhealthy($"Exception occurred while checking Well-Known endpoint {url}."); + unhealthyEndpoints.Add($"{url} (Exception: {ex.Message})"); } } + if (unhealthyEndpoints.Any()) + { + var description = $"The following endpoints are unhealthy: {string.Join(", ", unhealthyEndpoints)}"; + return HealthCheckResult.Unhealthy(description); + } + + return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); + return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); } } From 1cafcdf1286bc63862c8d7c4ebd5b9d459a5247f Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 19:27:29 +0200 Subject: [PATCH 07/49] Update src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../HealthChecks/WellKnownHealthChecks.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs index a329432aa..39367931d 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -33,6 +33,12 @@ public async Task CheckHealthAsync( .Select(section => section.GetValue("WellKnown")) .ToList(); + if (!wellKnownEndpoints.Any()) + { + _logger.LogWarning("No Well-Known endpoints found in configuration."); + return HealthCheckResult.Unhealthy("No Well-Known endpoints are configured."); + } + var client = _httpClientFactory.CreateClient("HealthCheckClient"); var unhealthyEndpoints = new List(); From 399606090a3e4e7d9e4fff8f3688289f221e6c75 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 19:31:24 +0200 Subject: [PATCH 08/49] cleanup --- .../HealthChecks/WellKnownHealthChecks.cs | 13 ++++++++----- .../InfrastructureExtensions.cs | 4 ++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs index 39367931d..ff1290e74 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -54,21 +54,24 @@ public async Task CheckHealthAsync( unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } } - catch (Exception ex) + catch (HttpRequestException ex) { _logger.LogError(ex, "Exception occurred while checking Well-Known endpoint: {Url}", url); - unhealthyEndpoints.Add($"{url} (Exception: {ex.Message})"); + return HealthCheckResult.Unhealthy($"Exception occurred while checking Well-Known endpoint {url}."); + } + catch (Exception ex) + { + _logger.LogError(ex, "An unexpected error occurred while checking Well-Known endpoint: {Url}", url); + return HealthCheckResult.Unhealthy($"An unexpected error occurred while checking Well-Known endpoint {url}."); } } - if (unhealthyEndpoints.Any()) + if (unhealthyEndpoints.Count > 0) { var description = $"The following endpoints are unhealthy: {string.Join(", ", unhealthyEndpoints)}"; return HealthCheckResult.Unhealthy(description); } return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); - - return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); } } diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 9103836ea..3c0389469 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -185,6 +185,10 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); services.AddHttpClient("HealthCheckClient") + .ConfigureHttpClient((services, client) => + { + client.Timeout = TimeSpan.FromSeconds(5); + }) .SetHandlerLifetime(TimeSpan.FromSeconds(10)); services.AddHealthChecks() From 8889b770140201f3d73bb680acbe614956092dc1 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 20 Sep 2024 19:33:55 +0200 Subject: [PATCH 09/49] cleanup --- .../HealthChecks/WellKnownHealthChecks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs index ff1290e74..490f32a8a 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -33,7 +33,7 @@ public async Task CheckHealthAsync( .Select(section => section.GetValue("WellKnown")) .ToList(); - if (!wellKnownEndpoints.Any()) + if (wellKnownEndpoints.Count == 0) { _logger.LogWarning("No Well-Known endpoints found in configuration."); return HealthCheckResult.Unhealthy("No Well-Known endpoints are configured."); From 02c13b0ab2039299cac57c9fd78de446d9e816a0 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 23 Sep 2024 13:21:40 +0200 Subject: [PATCH 10/49] cleanup --- .../InfrastructureExtensions.cs | 4 ++-- src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 3c0389469..a01b6cacf 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -202,11 +202,11 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi name: "postgres", healthQuery: "SELECT 1", failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies"]) + tags: ["dependencies", "critical"]) .AddCheck( "Well-Known Endpoints", failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies", "auth"]); + tags: ["dependencies"]); if (environment.IsDevelopment()) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index ab2208b6e..8d45760c3 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -210,12 +210,12 @@ static void BuildAndRun(string[] args) }); app.MapHealthChecks("/liveness", new HealthCheckOptions { - Predicate = check => check.Tags.Contains("self"), // Retains the self check for liveness + Predicate = check => check.Tags.Contains("self"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); app.MapHealthChecks("/readiness", new HealthCheckOptions { - Predicate = check => check.Tags.Contains("dependencies"), + Predicate = check => check.Tags.Contains("critical"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); app.MapHealthChecks("/health", new HealthCheckOptions From e9322f128f65809db26bf9bbb9eaae3febebbe4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Skogstad?= Date: Tue, 1 Oct 2024 14:51:13 +0200 Subject: [PATCH 11/49] Update src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs --- .../HealthChecks/WellKnownHealthChecks.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs index 490f32a8a..93f5a7efa 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs @@ -19,9 +19,9 @@ public WellKnownEndpointsHealthCheck( ILogger logger, IConfiguration configuration) { - _httpClientFactory = httpClientFactory; - _logger = logger; - _configuration = configuration; + _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); } public async Task CheckHealthAsync( From 383f56a8feb0a268cd043add6295b2201a204ec1 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Tue, 1 Oct 2024 17:17:29 +0200 Subject: [PATCH 12/49] chore: adjust health checks --- .azure/applications/web-api-eu/main.bicep | 33 +++++++++++++++++++++++ .azure/applications/web-api-so/main.bicep | 4 +++ .azure/modules/containerApp/main.bicep | 25 +++-------------- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/.azure/applications/web-api-eu/main.bicep b/.azure/applications/web-api-eu/main.bicep index 5458a454d..2f6b4a089 100644 --- a/.azure/applications/web-api-eu/main.bicep +++ b/.azure/applications/web-api-eu/main.bicep @@ -79,6 +79,38 @@ resource environmentKeyVaultResource 'Microsoft.KeyVault/vaults@2023-07-01' exis var containerAppName = '${namePrefix}-webapi-eu-ca' +var port = 8080 + +var probes = [ + { + periodSeconds: 5 + initialDelaySeconds: 2 + type: 'Liveness' + httpGet: { + path: '/liveness' + port: port + } + } + { + periodSeconds: 5 + initialDelaySeconds: 2 + type: 'Readiness' + httpGet: { + path: '/readiness' + port: port + } + } + { + periodSeconds: 5 + initialDelaySeconds: 2 + type: 'Startup' + httpGet: { + path: '/startup' + port: port + } + } +] + module containerApp '../../modules/containerApp/main.bicep' = { name: containerAppName params: { @@ -91,6 +123,7 @@ module containerApp '../../modules/containerApp/main.bicep' = { tags: tags resources: resources revisionSuffix: imageTag + probes: probes } } diff --git a/.azure/applications/web-api-so/main.bicep b/.azure/applications/web-api-so/main.bicep index e510fb86a..39f6e7eae 100644 --- a/.azure/applications/web-api-so/main.bicep +++ b/.azure/applications/web-api-so/main.bicep @@ -19,6 +19,9 @@ param apimIp string @description('CPU and memory resources for the container app') param resources object? +@description('The probes for the container app') +param probes array = [] + @description('The name of the container app environment') @minLength(3) @secure() @@ -95,6 +98,7 @@ module containerApp '../../modules/containerApp/main.bicep' = { tags: tags resources: resources revisionSuffix: imageTag + probes: probes } } diff --git a/.azure/modules/containerApp/main.bicep b/.azure/modules/containerApp/main.bicep index 29b75bb21..7eb404bef 100644 --- a/.azure/modules/containerApp/main.bicep +++ b/.azure/modules/containerApp/main.bicep @@ -28,30 +28,12 @@ param resources object? @description('The suffix for the revision of the container app') param revisionSuffix string +@description('The probes for the container app') +param probes array = [] + // Container app revision name does not allow '.' character var cleanedRevisionSuffix = replace(revisionSuffix, '.', '-') -var probes = [ - { - periodSeconds: 5 - initialDelaySeconds: 2 - type: 'Liveness' - httpGet: { - path: '/healthz' - port: port - } - } - { - periodSeconds: 5 - initialDelaySeconds: 2 - type: 'Readiness' - httpGet: { - path: '/healthz' - port: port - } - } -] - var ipSecurityRestrictions = empty(apimIp) ? [] : [ @@ -74,7 +56,6 @@ resource containerApp 'Microsoft.App/containerApps@2024-03-01' = { identity: { type: 'SystemAssigned' } - properties: { configuration: { ingress: ingress From 62bd90387a27847241ee90bb75faaddb76fbf2f2 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Tue, 1 Oct 2024 17:19:30 +0200 Subject: [PATCH 13/49] chore: adjust health checks --- .azure/applications/web-api-so/main.bicep | 36 +++++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/.azure/applications/web-api-so/main.bicep b/.azure/applications/web-api-so/main.bicep index 39f6e7eae..1e48c68f5 100644 --- a/.azure/applications/web-api-so/main.bicep +++ b/.azure/applications/web-api-so/main.bicep @@ -19,9 +19,6 @@ param apimIp string @description('CPU and memory resources for the container app') param resources object? -@description('The probes for the container app') -param probes array = [] - @description('The name of the container app environment') @minLength(3) @secure() @@ -86,6 +83,38 @@ resource environmentKeyVaultResource 'Microsoft.KeyVault/vaults@2023-07-01' exis var containerAppName = '${namePrefix}-webapi-so-ca' +var port = 8080 + +var probes = [ + { + periodSeconds: 5 + initialDelaySeconds: 2 + type: 'Liveness' + httpGet: { + path: '/liveness' + port: port + } + } + { + periodSeconds: 5 + initialDelaySeconds: 2 + type: 'Readiness' + httpGet: { + path: '/readiness' + port: port + } + } + { + periodSeconds: 5 + initialDelaySeconds: 2 + type: 'Startup' + httpGet: { + path: '/startup' + port: port + } + } +] + module containerApp '../../modules/containerApp/main.bicep' = { name: containerAppName params: { @@ -99,6 +128,7 @@ module containerApp '../../modules/containerApp/main.bicep' = { resources: resources revisionSuffix: imageTag probes: probes + port: port } } From 1129ce2a3b0ce9f7a222c1a327934d7068a4ed09 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Tue, 1 Oct 2024 17:23:43 +0200 Subject: [PATCH 14/49] cleanup --- .../InfrastructureExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index a01b6cacf..efdf8be06 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -189,7 +189,7 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi { client.Timeout = TimeSpan.FromSeconds(5); }) - .SetHandlerLifetime(TimeSpan.FromSeconds(10)); + .SetHandlerLifetime(TimeSpan.FromMinutes(2)); services.AddHealthChecks() .AddRedis( From 33e7c4e9416d57a6d8c4d3d71c22a153ef22a66a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 09:26:22 +0200 Subject: [PATCH 15/49] chore(deps): update dependency htmlagilitypack to 1.11.66 (#1212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [HtmlAgilityPack](http://html-agility-pack.net/) ([source](https://redirect.github.com/zzzprojects/html-agility-pack)) | `1.11.65` -> `1.11.66` | [![age](https://developer.mend.io/api/mc/badges/age/nuget/HtmlAgilityPack/1.11.66?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/nuget/HtmlAgilityPack/1.11.66?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/nuget/HtmlAgilityPack/1.11.65/1.11.66?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/HtmlAgilityPack/1.11.65/1.11.66?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
zzzprojects/html-agility-pack (HtmlAgilityPack) ### [`v1.11.66`](https://redirect.github.com/zzzprojects/html-agility-pack/releases/tag/v1.11.66) #### Download the library **[here](https://www.nuget.org/packages/HtmlAgilityPack/)** - **FIXED:** OptionOutputAsXml = true since version 1.11.65 crossorigin issue [#​569](https://redirect.github.com/zzzprojects/html-agility-pack/issues/569)
--- ### Configuration 📅 **Schedule**: Branch creation - "before 7am on Sunday,before 7am on Wednesday" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/digdir/dialogporten). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .../Digdir.Domain.Dialogporten.Application.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj b/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj index 5ea710514..5a8ac78de 100644 --- a/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj +++ b/src/Digdir.Domain.Dialogporten.Application/Digdir.Domain.Dialogporten.Application.csproj @@ -8,7 +8,7 @@ - + From 08e94cb7a26cc975367168d654647495f944e076 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Wed, 2 Oct 2024 14:20:03 +0200 Subject: [PATCH 16/49] ci: ensure unique revisions for deployments (#1211) There was an issue where if we re-run the same workflow for deployment, it would fail because of using the same revision suffix. Changing to passing in a revision suffix and using workflow run id and workflow attempt to ensure uniqueness. - #{issue number} - [ ] **Your** code builds clean without any errors or warnings - [ ] Manual testing done (required) - [ ] Relevant automated test added (if you find this hard, leave it and we'll help out) - [ ] Documentation is updated (either in `docs`-directory, Altinnpedia or a separate linked PR in [altinn-studio-docs.](https://github.com/Altinn/altinn-studio-docs), if applicable) - **New Features** - Introduced a new environment variable `REVISION_SUFFIX` for improved tracking of deployment revisions. - Added a `revisionSuffix` parameter across various Bicep configuration files to enhance deployment customization and versioning. - Standardized deployment names to include environment and version for consistency. - **Chores** - Enhanced deployment workflow structure without altering the overall functionality. --- .azure/applications/graphql/main.bicep | 6 +++++- .azure/applications/graphql/prod.bicepparam | 1 + .azure/applications/graphql/staging.bicepparam | 1 + .azure/applications/graphql/test.bicepparam | 1 + .azure/applications/web-api-eu/main.bicep | 6 +++++- .azure/applications/web-api-eu/prod.bicepparam | 1 + .azure/applications/web-api-eu/staging.bicepparam | 1 + .azure/applications/web-api-eu/test.bicepparam | 1 + .azure/applications/web-api-so/main.bicep | 6 +++++- .azure/applications/web-api-so/prod.bicepparam | 1 + .azure/applications/web-api-so/staging.bicepparam | 1 + .azure/applications/web-api-so/test.bicepparam | 1 + .github/workflows/action-deploy-apps.yml | 5 ++++- 13 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.azure/applications/graphql/main.bicep b/.azure/applications/graphql/main.bicep index fb4edc2d8..a931e5361 100644 --- a/.azure/applications/graphql/main.bicep +++ b/.azure/applications/graphql/main.bicep @@ -16,6 +16,10 @@ param location string @minLength(3) param apimIp string +@description('The suffix for the revision of the container app') +@minLength(3) +param revisionSuffix string + @description('CPU and memory resources for the container app') param resources object? @@ -87,7 +91,7 @@ module containerApp '../../modules/containerApp/main.bicep' = { apimIp: apimIp tags: tags resources: resources - revisionSuffix: imageTag + revisionSuffix: revisionSuffix } } diff --git a/.azure/applications/graphql/prod.bicepparam b/.azure/applications/graphql/prod.bicepparam index 84ff5332d..562917c43 100644 --- a/.azure/applications/graphql/prod.bicepparam +++ b/.azure/applications/graphql/prod.bicepparam @@ -4,6 +4,7 @@ param environment = 'prod' param location = 'norwayeast' param apimIp = '51.120.88.54' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/graphql/staging.bicepparam b/.azure/applications/graphql/staging.bicepparam index 5287dd839..d2d415801 100644 --- a/.azure/applications/graphql/staging.bicepparam +++ b/.azure/applications/graphql/staging.bicepparam @@ -4,6 +4,7 @@ param environment = 'staging' param location = 'norwayeast' param apimIp = '51.13.86.131' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/graphql/test.bicepparam b/.azure/applications/graphql/test.bicepparam index 8873fcd13..c5f6c464f 100644 --- a/.azure/applications/graphql/test.bicepparam +++ b/.azure/applications/graphql/test.bicepparam @@ -4,6 +4,7 @@ param environment = 'test' param location = 'norwayeast' param apimIp = '51.120.88.69' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/web-api-eu/main.bicep b/.azure/applications/web-api-eu/main.bicep index 2f6b4a089..b2301a93c 100644 --- a/.azure/applications/web-api-eu/main.bicep +++ b/.azure/applications/web-api-eu/main.bicep @@ -16,6 +16,10 @@ param location string @minLength(3) param apimIp string +@description('The suffix for the revision of the container app') +@minLength(3) +param revisionSuffix string + @description('CPU and memory resources for the container app') param resources object? @@ -122,8 +126,8 @@ module containerApp '../../modules/containerApp/main.bicep' = { apimIp: apimIp tags: tags resources: resources - revisionSuffix: imageTag probes: probes + revisionSuffix: revisionSuffix } } diff --git a/.azure/applications/web-api-eu/prod.bicepparam b/.azure/applications/web-api-eu/prod.bicepparam index 84ff5332d..562917c43 100644 --- a/.azure/applications/web-api-eu/prod.bicepparam +++ b/.azure/applications/web-api-eu/prod.bicepparam @@ -4,6 +4,7 @@ param environment = 'prod' param location = 'norwayeast' param apimIp = '51.120.88.54' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/web-api-eu/staging.bicepparam b/.azure/applications/web-api-eu/staging.bicepparam index 5287dd839..d2d415801 100644 --- a/.azure/applications/web-api-eu/staging.bicepparam +++ b/.azure/applications/web-api-eu/staging.bicepparam @@ -4,6 +4,7 @@ param environment = 'staging' param location = 'norwayeast' param apimIp = '51.13.86.131' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/web-api-eu/test.bicepparam b/.azure/applications/web-api-eu/test.bicepparam index 8873fcd13..c5f6c464f 100644 --- a/.azure/applications/web-api-eu/test.bicepparam +++ b/.azure/applications/web-api-eu/test.bicepparam @@ -4,6 +4,7 @@ param environment = 'test' param location = 'norwayeast' param apimIp = '51.120.88.69' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/web-api-so/main.bicep b/.azure/applications/web-api-so/main.bicep index 1e48c68f5..59b33b164 100644 --- a/.azure/applications/web-api-so/main.bicep +++ b/.azure/applications/web-api-so/main.bicep @@ -16,6 +16,10 @@ param location string @minLength(3) param apimIp string +@description('The suffix for the revision of the container app') +@minLength(3) +param revisionSuffix string + @description('CPU and memory resources for the container app') param resources object? @@ -126,9 +130,9 @@ module containerApp '../../modules/containerApp/main.bicep' = { apimIp: apimIp tags: tags resources: resources - revisionSuffix: imageTag probes: probes port: port + revisionSuffix: revisionSuffix } } diff --git a/.azure/applications/web-api-so/prod.bicepparam b/.azure/applications/web-api-so/prod.bicepparam index 84ff5332d..562917c43 100644 --- a/.azure/applications/web-api-so/prod.bicepparam +++ b/.azure/applications/web-api-so/prod.bicepparam @@ -4,6 +4,7 @@ param environment = 'prod' param location = 'norwayeast' param apimIp = '51.120.88.54' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/web-api-so/staging.bicepparam b/.azure/applications/web-api-so/staging.bicepparam index 5287dd839..d2d415801 100644 --- a/.azure/applications/web-api-so/staging.bicepparam +++ b/.azure/applications/web-api-so/staging.bicepparam @@ -4,6 +4,7 @@ param environment = 'staging' param location = 'norwayeast' param apimIp = '51.13.86.131' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/applications/web-api-so/test.bicepparam b/.azure/applications/web-api-so/test.bicepparam index 8873fcd13..c5f6c464f 100644 --- a/.azure/applications/web-api-so/test.bicepparam +++ b/.azure/applications/web-api-so/test.bicepparam @@ -4,6 +4,7 @@ param environment = 'test' param location = 'norwayeast' param apimIp = '51.120.88.69' param imageTag = readEnvironmentVariable('IMAGE_TAG') +param revisionSuffix = readEnvironmentVariable('REVISION_SUFFIX') // secrets param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.github/workflows/action-deploy-apps.yml b/.github/workflows/action-deploy-apps.yml index 35325f8d5..79a87e76f 100644 --- a/.github/workflows/action-deploy-apps.yml +++ b/.github/workflows/action-deploy-apps.yml @@ -149,6 +149,8 @@ jobs: permissions: id-token: write contents: read + env: + REVISION_SUFFIX: "${{ github.run_id }}-${{ inputs.version }}-${{ github.run_attempt}}" steps: - name: "Checkout GitHub Action" uses: actions/checkout@v4 @@ -159,7 +161,6 @@ jobs: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - name: Dryrun Deploy app ${{ matrix.name }}(${{ inputs.environment }}) uses: azure/arm-deploy@v2 if: ${{ inputs.dryRun }} @@ -167,6 +168,7 @@ jobs: env: # parameters IMAGE_TAG: ${{ inputs.version }} + REVISION_SUFFIX: ${{ env.REVISION_SUFFIX }} # secrets AZURE_CONTAINER_APP_ENVIRONMENT_NAME: ${{ secrets.AZURE_CONTAINER_APP_ENVIRONMENT_NAME }} AZURE_APP_INSIGHTS_CONNECTION_STRING: ${{ secrets.AZURE_APP_INSIGHTS_CONNECTION_STRING }} @@ -190,6 +192,7 @@ jobs: env: # parameters IMAGE_TAG: ${{ inputs.version }} + REVISION_SUFFIX: ${{ env.REVISION_SUFFIX }} # secrets AZURE_CONTAINER_APP_ENVIRONMENT_NAME: ${{ secrets.AZURE_CONTAINER_APP_ENVIRONMENT_NAME }} AZURE_APP_INSIGHTS_CONNECTION_STRING: ${{ secrets.AZURE_APP_INSIGHTS_CONNECTION_STRING }} From f8fe468189a26834d96646d5f2008b4dcaf4751f Mon Sep 17 00:00:00 2001 From: Dialogporten Automation Bot <164321870+dialogporten-bot@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:42:23 +0200 Subject: [PATCH 17/49] chore(main): release 1.20.1 (#1207) :robot: I have created a release *beep* *boop* --- ## [1.20.1](https://github.com/digdir/dialogporten/compare/v1.20.0...v1.20.1) (2024-10-02) ### Bug Fixes * Add separate settings for parties cache, don't cache invalid response from Altinn 2 ([#1194](https://github.com/digdir/dialogporten/issues/1194)) ([dbb79dc](https://github.com/digdir/dialogporten/commit/dbb79dc26cefc5f28c21a738f39199c36a49438f)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- CHANGELOG.md | 7 +++++++ version.txt | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2b34ce2d..0fbfed193 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [1.20.1](https://github.com/digdir/dialogporten/compare/v1.20.0...v1.20.1) (2024-10-02) + + +### Bug Fixes + +* Add separate settings for parties cache, don't cache invalid response from Altinn 2 ([#1194](https://github.com/digdir/dialogporten/issues/1194)) ([dbb79dc](https://github.com/digdir/dialogporten/commit/dbb79dc26cefc5f28c21a738f39199c36a49438f)) + ## [1.20.0](https://github.com/digdir/dialogporten/compare/v1.19.0...v1.20.0) (2024-09-30) diff --git a/version.txt b/version.txt index 398935591..0044d6cb9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.20.0 +1.20.1 From ea2400bc9408955ec990b4294f11f5c8fce8af44 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Wed, 2 Oct 2024 14:43:13 +0200 Subject: [PATCH 18/49] ci: send message on release created and successfully validated (#1185) # Description - Will send a message in Slack about a new release once it has finished all dry-runs. - Will send a new message per commit in `main` Potential improvements: - Update this message whenever the release is updated. We cannot specify ID so we need to store this somewhere along with the PR-number.. - Add more actions to the message. "Approve" for example should just do that. Approve the PR and merge it automatically. - Add action to promote to production ## Summary by CodeRabbit - **New Features** - Introduced a new job that sends formatted notifications to Slack upon successful deployment, enhancing communication regarding pull requests. - **Bug Fixes** - Minor formatting corrections made to improve the clarity of deployment configurations. --- .../ci-cd-pull-request-release-please.yml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.github/workflows/ci-cd-pull-request-release-please.yml b/.github/workflows/ci-cd-pull-request-release-please.yml index 77fd3e3e7..101dae168 100644 --- a/.github/workflows/ci-cd-pull-request-release-please.yml +++ b/.github/workflows/ci-cd-pull-request-release-please.yml @@ -63,3 +63,47 @@ jobs: region: norwayeast dryRun: true version: ${{ needs.get-current-version.outputs.version }}-${{ needs.generate-git-short-sha.outputs.gitShortSha }} + + send-slack-message: + name: Send Slack message + needs: [dry-run-deploy-infra-staging, dry-run-deploy-apps-staging] + runs-on: ubuntu-latest + steps: + - name: Slackify markdown in pull request body + id: slackify + uses: LoveToKnow/slackify-markdown-action@v1.1.1 + with: + text: ${{ github.event.pull_request.body }} + - name: Send GitHub slack message + id: slack + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: slackapi/slack-github-action@v1.27.0 + with: + channel-id: ${{ secrets.SLACK_CHANNEL_ID_FOR_RELEASES }} + payload: | + { + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": ${{ toJson(steps.slackify.outputs.text) }} + } + }, + { "type": "divider" }, + { + "type": "actions", + "elements": [ + { + "type": "button", + "text": { + "type": "plain_text", + "text": "Approve Release" + }, + "url": "https://github.com/${{ github.repository }}/pull/${{ github.event.pull_request.number }}" + } + ] + } + ] + } From b755f0c2527459f3fc68e3bd8bca4daee42075cc Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Wed, 2 Oct 2024 17:42:19 +0200 Subject: [PATCH 19/49] beginning --- ...gdir.Library.Entity.EntityFrameworkCore.csproj | 15 +++++++++++++++ .../HealthChecks/WellKnownHealthChecks.cs | 0 src/Digdir.Library.Utils.AspNet/SomeFile.cs | 1 + 3 files changed, 16 insertions(+) create mode 100644 src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj rename src/{Digdir.Domain.Dialogporten.Infrastructure => Digdir.Library.Utils.AspNet}/HealthChecks/WellKnownHealthChecks.cs (100%) create mode 100644 src/Digdir.Library.Utils.AspNet/SomeFile.cs diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj new file mode 100644 index 000000000..8509bdb02 --- /dev/null +++ b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj @@ -0,0 +1,15 @@ + + + + true + + + + + + + + + + + diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownHealthChecks.cs similarity index 100% rename from src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/WellKnownHealthChecks.cs rename to src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownHealthChecks.cs diff --git a/src/Digdir.Library.Utils.AspNet/SomeFile.cs b/src/Digdir.Library.Utils.AspNet/SomeFile.cs new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/src/Digdir.Library.Utils.AspNet/SomeFile.cs @@ -0,0 +1 @@ + \ No newline at end of file From 84f0941e40f702282011bc3ca868d4f20c3c9292 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 12:18:04 +0200 Subject: [PATCH 20/49] refactor --- .../InfrastructureExtensions.cs | 7 +-- .../Digdir.Domain.Dialogporten.WebApi.csproj | 3 +- .../Program.cs | 30 +++--------- ....Library.Entity.EntityFrameworkCore.csproj | 15 ------ .../Digdir.Library.Utils.AspNet.csproj | 13 +++++ .../HealthCheckExtensions.cs | 48 +++++++++++++++++++ ...ks.cs => WellKnownEndpointsHealthCheck.cs} | 6 +-- src/Digdir.Library.Utils.AspNet/SomeFile.cs | 1 - 8 files changed, 73 insertions(+), 50 deletions(-) delete mode 100644 src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj create mode 100644 src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj create mode 100644 src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs rename src/Digdir.Library.Utils.AspNet/HealthChecks/{WellKnownHealthChecks.cs => WellKnownEndpointsHealthCheck.cs} (96%) delete mode 100644 src/Digdir.Library.Utils.AspNet/SomeFile.cs diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 1c08f3a39..5c7d482c7 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -34,7 +34,6 @@ using StackExchange.Redis; using ZiggyCreatures.Caching.Fusion; using ZiggyCreatures.Caching.Fusion.NullObjects; -using Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; namespace Digdir.Domain.Dialogporten.Infrastructure; @@ -219,11 +218,7 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi name: "postgres", healthQuery: "SELECT 1", failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies", "critical"]) - .AddCheck( - "Well-Known Endpoints", - failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies"]); + tags: ["dependencies", "critical"]); if (environment.IsDevelopment()) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj index 1fc55ede1..d42754295 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj +++ b/src/Digdir.Domain.Dialogporten.WebApi/Digdir.Domain.Dialogporten.WebApi.csproj @@ -21,7 +21,8 @@ + -
+ \ No newline at end of file diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 8d45760c3..cb68a5aca 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -26,6 +26,7 @@ using Microsoft.Extensions.Diagnostics.HealthChecks; using NSwag; using Serilog; +using Digdir.Library.Utils.AspNet; // Using two-stage initialization to catch startup errors. Log.Logger = new LoggerConfiguration() @@ -126,14 +127,14 @@ static void BuildAndRun(string[] args) }; }) .AddControllers(options => options.InputFormatters.Insert(0, JsonPatchInputFormatter.Get())) - .AddNewtonsoftJson() .Services // Auth .AddDialogportenAuthentication(builder.Configuration) .AddAuthorization() - .AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]); + + // Health checks + .AddAspNetHealthChecks(); if (builder.Environment.IsDevelopment()) { @@ -203,26 +204,9 @@ static void BuildAndRun(string[] args) uiConfig.DocumentPath = dialogPrefix + "/swagger/{documentName}/swagger.json"; }); app.MapControllers(); - app.MapHealthChecks("/startup", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("dependencies"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("self"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/readiness", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("critical"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/health", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("dependencies"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); + + // Map Health Checks + app.MapAspNetHealthChecks(); app.Run(); } diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj deleted file mode 100644 index 8509bdb02..000000000 --- a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Entity.EntityFrameworkCore.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - true - - - - - - - - - - - diff --git a/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj new file mode 100644 index 000000000..f340a8f0a --- /dev/null +++ b/src/Digdir.Library.Utils.AspNet/Digdir.Library.Utils.AspNet.csproj @@ -0,0 +1,13 @@ + + + + true + 1591 + + + + + + + + diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs new file mode 100644 index 000000000..e48ff4aa9 --- /dev/null +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -0,0 +1,48 @@ +using Digdir.Library.Utils.AspNet.HealthChecks; +using HealthChecks.UI.Client; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; + +namespace Digdir.Library.Utils.AspNet; + +public static class HealthCheckExtensions +{ + public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services) + { + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]) + .AddCheck( + "Well-Known Endpoints", + failureStatus: HealthStatus.Unhealthy, + tags: ["dependencies"]); + + return services; + } + + public static void MapAspNetHealthChecks(this WebApplication app) + { + app.MapHealthChecks("/startup", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("dependencies"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.MapHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("self"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.MapHealthChecks("/readiness", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("critical"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + app.MapHealthChecks("/health", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("dependencies"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + } +} diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownHealthChecks.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownEndpointsHealthCheck.cs similarity index 96% rename from src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownHealthChecks.cs rename to src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownEndpointsHealthCheck.cs index 93f5a7efa..eee315a21 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownHealthChecks.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownEndpointsHealthCheck.cs @@ -4,9 +4,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -namespace Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; +namespace Digdir.Library.Utils.AspNet.HealthChecks; internal sealed class WellKnownEndpointsHealthCheck : IHealthCheck { @@ -40,7 +39,6 @@ public async Task CheckHealthAsync( } var client = _httpClientFactory.CreateClient("HealthCheckClient"); - var unhealthyEndpoints = new List(); foreach (var url in wellKnownEndpoints) @@ -74,4 +72,4 @@ public async Task CheckHealthAsync( return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); } -} +} \ No newline at end of file diff --git a/src/Digdir.Library.Utils.AspNet/SomeFile.cs b/src/Digdir.Library.Utils.AspNet/SomeFile.cs deleted file mode 100644 index 5f282702b..000000000 --- a/src/Digdir.Library.Utils.AspNet/SomeFile.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 4b8fdb64c18a19e8d40952358f43cb27ada3f6b6 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 12:38:00 +0200 Subject: [PATCH 21/49] refactor --- ....Domain.Dialogporten.Infrastructure.csproj | 5 ++- .../HealthChecks/RedisHealthCheck.cs | 32 +++++++++++++++++++ .../InfrastructureExtensions.cs | 19 ++++------- 3 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj index 0ab5f5e85..05959ff41 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj @@ -1,10 +1,7 @@  - - - @@ -19,6 +16,8 @@ runtime; build; native; contentfiles; analyzers; buildtransitive true + + diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs new file mode 100644 index 000000000..d2dd8c2bb --- /dev/null +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using StackExchange.Redis; + +namespace Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; + +public class RedisHealthCheck : IHealthCheck +{ + private readonly string _connectionString; + + public RedisHealthCheck(string connectionString) + { + _connectionString = connectionString; + } + + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) + { + try + { + var redis = await ConnectionMultiplexer.ConnectAsync(_connectionString); + var db = redis.GetDatabase(); + await db.PingAsync(); + return HealthCheckResult.Healthy(); + } + catch (Exception ex) + { + return HealthCheckResult.Unhealthy(exception: ex); + } + } +} \ No newline at end of file diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 5c7d482c7..e9a26ebcc 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -30,10 +30,11 @@ using Digdir.Domain.Dialogporten.Infrastructure.Persistence.Configurations.Actors; using Digdir.Domain.Dialogporten.Infrastructure.Persistence.Repositories; using HotChocolate.Subscriptions; -using Microsoft.Extensions.Diagnostics.HealthChecks; using StackExchange.Redis; using ZiggyCreatures.Caching.Fusion; using ZiggyCreatures.Caching.Fusion.NullObjects; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; namespace Digdir.Domain.Dialogporten.Infrastructure; @@ -208,18 +209,12 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi .SetHandlerLifetime(TimeSpan.FromMinutes(2)); services.AddHealthChecks() - .AddRedis( - redisConnectionString: infrastructureSettings.Redis.ConnectionString, - name: "redis", - failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies"]) - .AddNpgSql( - connectionString: infrastructureSettings.DialogDbConnectionString, - name: "postgres", - healthQuery: "SELECT 1", - failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies", "critical"]); + .AddCheck("redis", tags: ["dependencies", "redis"]); + services.AddSingleton(sp => new RedisHealthCheck(infrastructureSettings.Redis.ConnectionString)); + + services.AddHealthChecks() + .AddDbContextCheck("postgres", tags: ["dependencies", "critical"]); if (environment.IsDevelopment()) { From 59ef954152f9040e5aca626afdf571d92e81e8fa Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 12:44:11 +0200 Subject: [PATCH 22/49] ok --- .../Digdir.Domain.Dialogporten.Infrastructure.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj index 05959ff41..0ae0cc974 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/Digdir.Domain.Dialogporten.Infrastructure.csproj @@ -7,7 +7,6 @@ - From 2ca9fae1f2f623f64b6c2032a76d9277c9b10e70 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 14:01:23 +0200 Subject: [PATCH 23/49] ok --- .../Program.cs | 9 ++-- .../HealthCheckExtensions.cs | 33 ++++++++++++-- ...HealthCheck.cs => EndpointsHealthCheck.cs} | 45 ++++++++++--------- 3 files changed, 59 insertions(+), 28 deletions(-) rename src/Digdir.Library.Utils.AspNet/HealthChecks/{WellKnownEndpointsHealthCheck.cs => EndpointsHealthCheck.cs} (59%) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index cb68a5aca..0ac563ca9 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -133,8 +133,11 @@ static void BuildAndRun(string[] args) .AddDialogportenAuthentication(builder.Configuration) .AddAuthorization() - // Health checks - .AddAspNetHealthChecks(); + // Health checks with configuration + .AddAspNetHealthChecks(options => + { + options.WellKnownEndpointsConfigurationSectionPath = "WebApi:Authentication:JwtBearerTokenSchemas"; + }); if (builder.Environment.IsDevelopment()) { @@ -223,4 +226,4 @@ static void IgnoreEmptyCollections(JsonTypeInfo typeInfo) } // ReSharper disable once ClassNeverInstantiated.Global -public sealed partial class Program; +public sealed partial class Program; \ No newline at end of file diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index e48ff4aa9..e4be08deb 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -10,12 +10,39 @@ namespace Digdir.Library.Utils.AspNet; public static class HealthCheckExtensions { - public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services) + public class AspNetHealthChecksOptions { + public string WellKnownEndpointsConfigurationSectionPath { get; set; } = string.Empty; + } + + public class JwtBearerTokenSchema + { + public string Name { get; set; } = string.Empty; + public string WellKnown { get; set; } = string.Empty; + } + + public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, Action configure) + { + var options = new AspNetHealthChecksOptions(); + configure(options); + + var wellKnownSchemas = services.BuildServiceProvider() + .GetRequiredService() + .GetSection(options.WellKnownEndpointsConfigurationSectionPath) + .Get>(); + + var wellKnownEndpoints = wellKnownSchemas?.Select(schema => schema.WellKnown).ToList() ?? new List(); + + services.Configure(opts => + { + opts.Endpoints = wellKnownEndpoints; + }); + + // Register the health checks services.AddHealthChecks() .AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]) - .AddCheck( - "Well-Known Endpoints", + .AddCheck( + "Endpoints", failureStatus: HealthStatus.Unhealthy, tags: ["dependencies"]); diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownEndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs similarity index 59% rename from src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownEndpointsHealthCheck.cs rename to src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index eee315a21..a33ec524d 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/WellKnownEndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -4,63 +4,59 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Digdir.Library.Utils.AspNet.HealthChecks; -internal sealed class WellKnownEndpointsHealthCheck : IHealthCheck +internal sealed class EndpointsHealthCheck : IHealthCheck { private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; - private readonly IConfiguration _configuration; + private readonly ILogger _logger; + private readonly List _endpoints; - public WellKnownEndpointsHealthCheck( + public EndpointsHealthCheck( IHttpClientFactory httpClientFactory, - ILogger logger, - IConfiguration configuration) + ILogger logger, + IOptions options) { _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + _endpoints = options?.Value?.Endpoints ?? throw new ArgumentNullException(nameof(options)); } public async Task CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { - var wellKnownEndpoints = _configuration.GetSection("WebApi:Authentication:JwtBearerTokenSchemas") - .GetChildren() - .Select(section => section.GetValue("WellKnown")) - .ToList(); - - if (wellKnownEndpoints.Count == 0) + if (_endpoints.Count == 0) { - _logger.LogWarning("No Well-Known endpoints found in configuration."); - return HealthCheckResult.Unhealthy("No Well-Known endpoints are configured."); + _logger.LogWarning("No endpoints provided."); + return HealthCheckResult.Unhealthy("No endpoints are configured."); } var client = _httpClientFactory.CreateClient("HealthCheckClient"); var unhealthyEndpoints = new List(); - foreach (var url in wellKnownEndpoints) + foreach (var url in _endpoints) { try { var response = await client.GetAsync(url, cancellationToken); if (!response.IsSuccessStatusCode) { - _logger.LogWarning("Health check failed for Well-Known endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); + _logger.LogWarning("Health check failed for endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } } catch (HttpRequestException ex) { - _logger.LogError(ex, "Exception occurred while checking Well-Known endpoint: {Url}", url); - return HealthCheckResult.Unhealthy($"Exception occurred while checking Well-Known endpoint {url}."); + _logger.LogError(ex, "Exception occurred while checking endpoint: {Url}", url); + return HealthCheckResult.Unhealthy($"Exception occurred while checking endpoint {url}."); } catch (Exception ex) { - _logger.LogError(ex, "An unexpected error occurred while checking Well-Known endpoint: {Url}", url); - return HealthCheckResult.Unhealthy($"An unexpected error occurred while checking Well-Known endpoint {url}."); + _logger.LogError(ex, "An unexpected error occurred while checking endpoint: {Url}", url); + return HealthCheckResult.Unhealthy($"An unexpected error occurred while checking endpoint {url}."); } } @@ -70,6 +66,11 @@ public async Task CheckHealthAsync( return HealthCheckResult.Unhealthy(description); } - return HealthCheckResult.Healthy("All Well-Known endpoints are healthy."); + return HealthCheckResult.Healthy("All endpoints are healthy."); } +} + +public class EndpointsHealthCheckOptions +{ + public List Endpoints { get; set; } = new(); } \ No newline at end of file From e41bd023aae7a87fee911cfd4af20a63c72e3756 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 14:08:37 +0200 Subject: [PATCH 24/49] swaggah --- docs/schema/V1/swagger.verified.json | 36 +++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index 85147c0a5..a50e67019 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -2552,6 +2552,33 @@ "CONNECT" ] }, + "IContractResolver": { + "additionalProperties": false, + "description": "Used by JsonSerializer to resolve a JsonContract for a given Type.", + "type": "object", + "x-abstract": true + }, + "JsonPatchDocumentOfUpdateDialogDto": { + "additionalProperties": false, + "properties": { + "contractResolver": { + "nullable": true, + "oneOf": [ + { + "$ref": "#/components/schemas/IContractResolver" + } + ] + }, + "operations": { + "items": { + "$ref": "#/components/schemas/OperationOfUpdateDialogDto" + }, + "nullable": true, + "type": "array" + } + }, + "type": "object" + }, "Jwk": { "additionalProperties": false, "properties": { @@ -2615,7 +2642,7 @@ "Exists" ] }, - "Operation": { + "OperationOfUpdateDialogDto": { "additionalProperties": false, "properties": { "from": { @@ -5475,10 +5502,7 @@ "content": { "application/json": { "schema": { - "items": { - "$ref": "#/components/schemas/Operation" - }, - "type": "array" + "$ref": "#/components/schemas/JsonPatchDocumentOfUpdateDialogDto" } } }, @@ -6460,4 +6484,4 @@ "url": "https://altinn-dev-api.azure-api.net/dialogporten" } ] -} +} \ No newline at end of file From fcf6727955a7cefb7b46e38c6b8469060b84965c Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:09:32 +0200 Subject: [PATCH 25/49] cleanup --- .../InfrastructureExtensions.cs | 33 +++++++++++-------- .../Program.cs | 3 -- .../HealthCheckExtensions.cs | 1 - 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index e9a26ebcc..7aa316ea4 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -201,20 +201,7 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi }) .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); - services.AddHttpClient("HealthCheckClient") - .ConfigureHttpClient((services, client) => - { - client.Timeout = TimeSpan.FromSeconds(5); - }) - .SetHandlerLifetime(TimeSpan.FromMinutes(2)); - - services.AddHealthChecks() - .AddCheck("redis", tags: ["dependencies", "redis"]); - - services.AddSingleton(sp => new RedisHealthCheck(infrastructureSettings.Redis.ConnectionString)); - - services.AddHealthChecks() - .AddDbContextCheck("postgres", tags: ["dependencies", "critical"]); + services.AddHealthChecks(infrastructureSettings); if (environment.IsDevelopment()) { @@ -229,6 +216,24 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi return services; } + private static IServiceCollection AddHealthChecks(this IServiceCollection services, InfrastructureSettings configuration) + { + services.AddHttpClient("HealthCheckClient") + .ConfigureHttpClient((services, client) => + { + client.Timeout = TimeSpan.FromSeconds(5); + }) + .SetHandlerLifetime(TimeSpan.FromMinutes(2)); + + services.AddHealthChecks() + .AddCheck("redis", tags: ["dependencies", "redis"]) + .AddDbContextCheck("postgres", tags: ["dependencies", "critical"]); + + services.AddSingleton(sp => new RedisHealthCheck(configuration.Redis.ConnectionString)); + + return services; + } + private static IServiceCollection AddGraphQlRedisSubscriptions(this IServiceCollection services, string redisConnectionString) { diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 0ac563ca9..3236fcb58 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -19,11 +19,8 @@ using FastEndpoints; using FastEndpoints.Swagger; using FluentValidation; -using HealthChecks.UI.Client; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; using NSwag; using Serilog; using Digdir.Library.Utils.AspNet; diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index e4be08deb..d4b5260e8 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -45,7 +45,6 @@ public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection s "Endpoints", failureStatus: HealthStatus.Unhealthy, tags: ["dependencies"]); - return services; } From 34ce8a83ed09bf9fdff83b639716fba015fe1bcc Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:18:13 +0200 Subject: [PATCH 26/49] cleanup --- .../HealthChecks/RedisHealthCheck.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs index d2dd8c2bb..29ff93c46 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -6,7 +6,7 @@ namespace Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; -public class RedisHealthCheck : IHealthCheck +internal sealed class RedisHealthCheck : IHealthCheck { private readonly string _connectionString; From 62ced3e44546dc7bc30a77e8ab580a3d6e2b1267 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:20:22 +0200 Subject: [PATCH 27/49] cleanup --- src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 3236fcb58..713718847 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -124,7 +124,8 @@ static void BuildAndRun(string[] args) }; }) .AddControllers(options => options.InputFormatters.Insert(0, JsonPatchInputFormatter.Get())) - .Services + .AddNewtonsoftJson() + .Services // Auth .AddDialogportenAuthentication(builder.Configuration) From 3abf115ec0afa75d9ab201f4837174051d260020 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:20:57 +0200 Subject: [PATCH 28/49] Update src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../HealthChecks/RedisHealthCheck.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs index 29ff93c46..735487bc0 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -19,14 +19,18 @@ public async Task CheckHealthAsync(HealthCheckContext context { try { - var redis = await ConnectionMultiplexer.ConnectAsync(_connectionString); + using var redis = await ConnectionMultiplexer.ConnectAsync(_connectionString); var db = redis.GetDatabase(); await db.PingAsync(); - return HealthCheckResult.Healthy(); + return HealthCheckResult.Healthy("Redis connection is healthy."); + } + catch (RedisConnectionException ex) + { + return HealthCheckResult.Unhealthy("Unable to connect to Redis.", exception: ex); } catch (Exception ex) { - return HealthCheckResult.Unhealthy(exception: ex); + return HealthCheckResult.Unhealthy("An unexpected error occurred while checking Redis health.", exception: ex); } } } \ No newline at end of file From 3173da95bd0530a5ab81cbf09c12df530f002d6a Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:26:56 +0200 Subject: [PATCH 29/49] cleanup --- .../HealthChecks/RedisHealthCheck.cs | 9 +++++---- .../InfrastructureExtensions.cs | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs index 735487bc0..91f8fc411 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -3,23 +3,24 @@ using System.Threading.Tasks; using Microsoft.Extensions.Diagnostics.HealthChecks; using StackExchange.Redis; +using Microsoft.Extensions.Options; namespace Digdir.Domain.Dialogporten.Infrastructure.HealthChecks; internal sealed class RedisHealthCheck : IHealthCheck { - private readonly string _connectionString; + private readonly InfrastructureSettings _settings; - public RedisHealthCheck(string connectionString) + public RedisHealthCheck(IOptions options) { - _connectionString = connectionString; + _settings = options.Value; } public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) { try { - using var redis = await ConnectionMultiplexer.ConnectAsync(_connectionString); + using var redis = await ConnectionMultiplexer.ConnectAsync(_settings.Redis.ConnectionString); var db = redis.GetDatabase(); await db.PingAsync(); return HealthCheckResult.Healthy("Redis connection is healthy."); diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 7aa316ea4..27831d169 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -201,7 +201,7 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi }) .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); - services.AddHealthChecks(infrastructureSettings); + services.AddCustomHealthChecks(); if (environment.IsDevelopment()) { @@ -216,7 +216,7 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi return services; } - private static IServiceCollection AddHealthChecks(this IServiceCollection services, InfrastructureSettings configuration) + private static IServiceCollection AddCustomHealthChecks(this IServiceCollection services) { services.AddHttpClient("HealthCheckClient") .ConfigureHttpClient((services, client) => @@ -229,7 +229,7 @@ private static IServiceCollection AddHealthChecks(this IServiceCollection servic .AddCheck("redis", tags: ["dependencies", "redis"]) .AddDbContextCheck("postgres", tags: ["dependencies", "critical"]); - services.AddSingleton(sp => new RedisHealthCheck(configuration.Redis.ConnectionString)); + services.AddSingleton(); return services; } @@ -317,4 +317,4 @@ private static IServiceCollection ConfigureFusionCache(this IServiceCollection s return services; } -} +} \ No newline at end of file From 2f267c85f820d63c41008b8ffd07f430cd5a517c Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:35:01 +0200 Subject: [PATCH 30/49] cleanup --- .../InfrastructureExtensions.cs | 3 +-- src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 2 +- src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs | 5 ++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 27831d169..e39deb516 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -222,8 +222,7 @@ private static IServiceCollection AddCustomHealthChecks(this IServiceCollection .ConfigureHttpClient((services, client) => { client.Timeout = TimeSpan.FromSeconds(5); - }) - .SetHandlerLifetime(TimeSpan.FromMinutes(2)); + }); services.AddHealthChecks() .AddCheck("redis", tags: ["dependencies", "redis"]) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 713718847..d2c088433 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -132,7 +132,7 @@ static void BuildAndRun(string[] args) .AddAuthorization() // Health checks with configuration - .AddAspNetHealthChecks(options => + .AddAspNetHealthChecks(builder.Configuration, options => { options.WellKnownEndpointsConfigurationSectionPath = "WebApi:Authentication:JwtBearerTokenSchemas"; }); diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index d4b5260e8..76a6a7ba6 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -21,13 +21,12 @@ public class JwtBearerTokenSchema public string WellKnown { get; set; } = string.Empty; } - public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, Action configure) + public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, IConfiguration configuration, Action configure) { var options = new AspNetHealthChecksOptions(); configure(options); - var wellKnownSchemas = services.BuildServiceProvider() - .GetRequiredService() + var wellKnownSchemas = configuration .GetSection(options.WellKnownEndpointsConfigurationSectionPath) .Get>(); From 48bab84629c10672c10d0748bd818aca02e7881c Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:39:41 +0200 Subject: [PATCH 31/49] cleanup --- docs/schema/V1/swagger.verified.json | 29 +------------------ .../HealthChecks/EndpointsHealthCheck.cs | 8 ++--- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index a50e67019..b91a28310 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -2552,33 +2552,6 @@ "CONNECT" ] }, - "IContractResolver": { - "additionalProperties": false, - "description": "Used by JsonSerializer to resolve a JsonContract for a given Type.", - "type": "object", - "x-abstract": true - }, - "JsonPatchDocumentOfUpdateDialogDto": { - "additionalProperties": false, - "properties": { - "contractResolver": { - "nullable": true, - "oneOf": [ - { - "$ref": "#/components/schemas/IContractResolver" - } - ] - }, - "operations": { - "items": { - "$ref": "#/components/schemas/OperationOfUpdateDialogDto" - }, - "nullable": true, - "type": "array" - } - }, - "type": "object" - }, "Jwk": { "additionalProperties": false, "properties": { @@ -2642,7 +2615,7 @@ "Exists" ] }, - "OperationOfUpdateDialogDto": { + "Operation": { "additionalProperties": false, "properties": { "from": { diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index a33ec524d..9da4c5999 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -51,12 +51,12 @@ public async Task CheckHealthAsync( catch (HttpRequestException ex) { _logger.LogError(ex, "Exception occurred while checking endpoint: {Url}", url); - return HealthCheckResult.Unhealthy($"Exception occurred while checking endpoint {url}."); + unhealthyEndpoints.Add($"{url} (Exception: {ex.GetType().Name})"); } catch (Exception ex) { - _logger.LogError(ex, "An unexpected error occurred while checking endpoint: {Url}", url); - return HealthCheckResult.Unhealthy($"An unexpected error occurred while checking endpoint {url}."); + _logger.LogError(ex, "Exception occurred while checking endpoint: {Url}", url); + unhealthyEndpoints.Add($"{url} (Exception: {ex.GetType().Name})"); } } @@ -70,7 +70,7 @@ public async Task CheckHealthAsync( } } -public class EndpointsHealthCheckOptions +internal sealed class EndpointsHealthCheckOptions { public List Endpoints { get; set; } = new(); } \ No newline at end of file From 1a4dddb283ea63c1218bf02cbaf814bc4f9f9120 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:49:20 +0200 Subject: [PATCH 32/49] cleanup --- docs/schema/V1/swagger.verified.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/schema/V1/swagger.verified.json b/docs/schema/V1/swagger.verified.json index b91a28310..6c84bec1f 100644 --- a/docs/schema/V1/swagger.verified.json +++ b/docs/schema/V1/swagger.verified.json @@ -5475,7 +5475,10 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/JsonPatchDocumentOfUpdateDialogDto" + "items": { + "$ref": "#/components/schemas/Operation" + }, + "type": "array" } } }, From 296c01bbe130cd36d399abafdd4b35d05e24cc71 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:50:24 +0200 Subject: [PATCH 33/49] Update src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../HealthChecks/RedisHealthCheck.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs index 91f8fc411..713528106 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -13,6 +13,14 @@ internal sealed class RedisHealthCheck : IHealthCheck public RedisHealthCheck(IOptions options) { + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + if (options.Value == null) + { + throw new ArgumentException("InfrastructureSettings cannot be null.", nameof(options)); + } _settings = options.Value; } From 4038e3bfa760b66cd9dc33b8555b890584ba9ac2 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:52:03 +0200 Subject: [PATCH 34/49] cleanup --- .../HealthChecks/RedisHealthCheck.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs index 713528106..04e632cdd 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -13,10 +13,7 @@ internal sealed class RedisHealthCheck : IHealthCheck public RedisHealthCheck(IOptions options) { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } + ArgumentNullException.ThrowIfNull(options); if (options.Value == null) { throw new ArgumentException("InfrastructureSettings cannot be null.", nameof(options)); From f5eea3afad715a40aa9d9661610460b61f72865d Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 15:54:12 +0200 Subject: [PATCH 35/49] cleanup --- .../InfrastructureExtensions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index e39deb516..67924ddd3 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -219,10 +219,11 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi private static IServiceCollection AddCustomHealthChecks(this IServiceCollection services) { services.AddHttpClient("HealthCheckClient") - .ConfigureHttpClient((services, client) => + .ConfigureHttpClient(client => { client.Timeout = TimeSpan.FromSeconds(5); - }); + }) + .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); ; services.AddHealthChecks() .AddCheck("redis", tags: ["dependencies", "redis"]) From 12108643bc9233836bc0d303b739b71431771e6a Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 16:00:12 +0200 Subject: [PATCH 36/49] cleanup --- .../HealthCheckExtensions.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index 76a6a7ba6..80f10b6ba 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -30,20 +30,25 @@ public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection s .GetSection(options.WellKnownEndpointsConfigurationSectionPath) .Get>(); + var healthChecks = services.AddHealthChecks(); + + healthChecks.AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]); + var wellKnownEndpoints = wellKnownSchemas?.Select(schema => schema.WellKnown).ToList() ?? new List(); - services.Configure(opts => + if (wellKnownEndpoints.Count > 0) { - opts.Endpoints = wellKnownEndpoints; - }); + services.Configure(opts => + { + opts.Endpoints = wellKnownEndpoints; + }); - // Register the health checks - services.AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]) - .AddCheck( + healthChecks.AddCheck( "Endpoints", failureStatus: HealthStatus.Unhealthy, tags: ["dependencies"]); + } + return services; } From 4ba55db43a0b3fea0afea79283791012f9e82272 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Thu, 3 Oct 2024 16:00:41 +0200 Subject: [PATCH 37/49] Update src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../HealthChecks/EndpointsHealthCheck.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index 9da4c5999..d19e10680 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -48,11 +48,6 @@ public async Task CheckHealthAsync( unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } } - catch (HttpRequestException ex) - { - _logger.LogError(ex, "Exception occurred while checking endpoint: {Url}", url); - unhealthyEndpoints.Add($"{url} (Exception: {ex.GetType().Name})"); - } catch (Exception ex) { _logger.LogError(ex, "Exception occurred while checking endpoint: {Url}", url); From f1b0186fe635f5f448c8e63b583f7d73f41653d8 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 4 Oct 2024 09:52:39 +0200 Subject: [PATCH 38/49] Update src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ole Jørgen Skogstad --- .../HealthChecks/RedisHealthCheck.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs index 04e632cdd..4e88b8be6 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/HealthChecks/RedisHealthCheck.cs @@ -13,12 +13,7 @@ internal sealed class RedisHealthCheck : IHealthCheck public RedisHealthCheck(IOptions options) { - ArgumentNullException.ThrowIfNull(options); - if (options.Value == null) - { - throw new ArgumentException("InfrastructureSettings cannot be null.", nameof(options)); - } - _settings = options.Value; + _settings = options?.Value ?? throw new ArgumentNullException(nameof(options)); } public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) From dd80084d248434b0b5a54a5b8256050d17ff9bd6 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Fri, 4 Oct 2024 11:07:52 +0200 Subject: [PATCH 39/49] add to sln --- Digdir.Domain.Dialogporten.sln | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Digdir.Domain.Dialogporten.sln b/Digdir.Domain.Dialogporten.sln index f210c8fc2..03a375142 100644 --- a/Digdir.Domain.Dialogporten.sln +++ b/Digdir.Domain.Dialogporten.sln @@ -63,6 +63,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Domain.Dialogporten.Architecture.Tests", "tests\Digdir.Domain.Dialogporten.Architecture.Tests\Digdir.Domain.Dialogporten.Architecture.Tests.csproj", "{E389C7C8-9610-40AC-86DC-769B1B7DC78E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digdir.Library.Utils.AspNet", "src\Digdir.Library.Utils.AspNet\Digdir.Library.Utils.AspNet.csproj", "{6A485C65-3613-4A49-A16F-2789119F6F38}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -153,6 +155,10 @@ Global {E389C7C8-9610-40AC-86DC-769B1B7DC78E}.Debug|Any CPU.Build.0 = Debug|Any CPU {E389C7C8-9610-40AC-86DC-769B1B7DC78E}.Release|Any CPU.ActiveCfg = Release|Any CPU {E389C7C8-9610-40AC-86DC-769B1B7DC78E}.Release|Any CPU.Build.0 = Release|Any CPU + {6A485C65-3613-4A49-A16F-2789119F6F38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A485C65-3613-4A49-A16F-2789119F6F38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A485C65-3613-4A49-A16F-2789119F6F38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A485C65-3613-4A49-A16F-2789119F6F38}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -182,6 +188,7 @@ Global {AF35FFCA-1206-4C08-A003-DA4A1344CCD5} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7} {0900E3CF-F9D8-4B29-957F-484B3B028D6D} = {320B47A0-5EB8-4B6E-8C84-90633A1849CA} {E389C7C8-9610-40AC-86DC-769B1B7DC78E} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7} + {6A485C65-3613-4A49-A16F-2789119F6F38} = {320B47A0-5EB8-4B6E-8C84-90633A1849CA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B2FE67FF-7622-4AFB-AD8E-961B6A39D888} From f6d385b5046cad1fcde5f08210b981cd30fd3868 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 11:48:43 +0200 Subject: [PATCH 40/49] doc --- .../Program.cs | 68 +++++++++++-------- .../HealthCheckExtensions.cs | 41 +++++------ .../HealthChecks/EndpointsHealthCheck.cs | 6 -- 3 files changed, 57 insertions(+), 58 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index d2c088433..4e963f4d2 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -130,12 +130,25 @@ static void BuildAndRun(string[] args) // Auth .AddDialogportenAuthentication(builder.Configuration) .AddAuthorization() - + // options.WellKnownEndpointsConfigurationSectionPath = "WebApi:Authentication:JwtBearerTokenSchemas"; // Health checks with configuration - .AddAspNetHealthChecks(builder.Configuration, options => - { - options.WellKnownEndpointsConfigurationSectionPath = "WebApi:Authentication:JwtBearerTokenSchemas"; - }); + .AddAspNetHealthChecks(builder.Configuration.GetSection("AspNetHealthChecks").Get()); + + // Retrieve JWT bearer token schema URLs from configuration + var jwtBearerTokenSchemas = builder.Configuration + .GetSection("WebApi:Authentication:JwtBearerTokenSchemas") + .Get>(); + + var wellKnownUrls = jwtBearerTokenSchemas? + .Select(schema => schema.WellKnown) + .Where(url => !string.IsNullOrEmpty(url)) + .ToList() ?? new List(); + + // Add health checks with the retrieved URLs + builder.Services.AddAspNetHealthChecks(new AspNetHealthChecksSettings + { + HttpGetEndpointsToCheck = wellKnownUrls + }); if (builder.Environment.IsDevelopment()) { @@ -160,25 +173,11 @@ static void BuildAndRun(string[] args) .UseAuthorization() .UseServiceOwnerOnBehalfOfPerson() .UseUserTypeValidation() - .UseAzureConfiguration() - .UseFastEndpoints(x => - { - x.Endpoints.RoutePrefix = "api"; - x.Versioning.Prefix = "v"; - x.Versioning.PrependToRoute = true; - x.Versioning.DefaultVersion = 1; - x.Serializer.Options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; - // Do not serialize empty collections - x.Serializer.Options.TypeInfoResolver = new DefaultJsonTypeInfoResolver - { - Modifiers = { IgnoreEmptyCollections } - }; - x.Serializer.Options.Converters.Add(new JsonStringEnumConverter()); - x.Serializer.Options.Converters.Add(new UtcDateTimeOffsetConverter()); - x.Serializer.Options.Converters.Add(new DateTimeNotSupportedConverter()); - x.Errors.ResponseBuilder = ErrorResponseBuilderExtensions.ResponseBuilder; - }) - .UseAddSwaggerCorsHeader() + .UseAzureConfiguration(); + + app.MapAspNetHealthChecks(); + + app.UseAddSwaggerCorsHeader() .UseSwaggerGen(config => { config.PostProcess = (document, _) => @@ -203,11 +202,26 @@ static void BuildAndRun(string[] args) // We have to add dialogporten here to get the correct base url for swagger.json in the APIM. Should not be done for development var dialogPrefix = builder.Environment.IsDevelopment() ? "" : "/dialogporten"; uiConfig.DocumentPath = dialogPrefix + "/swagger/{documentName}/swagger.json"; + }) + .UseFastEndpoints(x => + { + x.Endpoints.RoutePrefix = "api"; + x.Versioning.Prefix = "v"; + x.Versioning.PrependToRoute = true; + x.Versioning.DefaultVersion = 1; + x.Serializer.Options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + // Do not serialize empty collections + x.Serializer.Options.TypeInfoResolver = new DefaultJsonTypeInfoResolver + { + Modifiers = { IgnoreEmptyCollections } + }; + x.Serializer.Options.Converters.Add(new JsonStringEnumConverter()); + x.Serializer.Options.Converters.Add(new UtcDateTimeOffsetConverter()); + x.Serializer.Options.Converters.Add(new DateTimeNotSupportedConverter()); + x.Errors.ResponseBuilder = ErrorResponseBuilderExtensions.ResponseBuilder; }); - app.MapControllers(); - // Map Health Checks - app.MapAspNetHealthChecks(); + app.MapControllers(); app.Run(); } diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index 80f10b6ba..d960d25bd 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -10,61 +10,46 @@ namespace Digdir.Library.Utils.AspNet; public static class HealthCheckExtensions { - public class AspNetHealthChecksOptions + public class AspNetHealthChecksSettings { - public string WellKnownEndpointsConfigurationSectionPath { get; set; } = string.Empty; + public List? HttpGetEndpointsToCheck { get; set; } } - public class JwtBearerTokenSchema + public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, AspNetHealthChecksSettings settings) { - public string Name { get; set; } = string.Empty; - public string WellKnown { get; set; } = string.Empty; - } - - public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, IConfiguration configuration, Action configure) - { - var options = new AspNetHealthChecksOptions(); - configure(options); - - var wellKnownSchemas = configuration - .GetSection(options.WellKnownEndpointsConfigurationSectionPath) - .Get>(); - var healthChecks = services.AddHealthChecks(); healthChecks.AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]); - var wellKnownEndpoints = wellKnownSchemas?.Select(schema => schema.WellKnown).ToList() ?? new List(); - - if (wellKnownEndpoints.Count > 0) + if (settings.HttpGetEndpointsToCheck != null && settings.HttpGetEndpointsToCheck.Count > 0) { services.Configure(opts => { - opts.Endpoints = wellKnownEndpoints; + opts.Endpoints = settings.HttpGetEndpointsToCheck; }); healthChecks.AddCheck( "Endpoints", failureStatus: HealthStatus.Unhealthy, - tags: ["dependencies"]); + tags: ["external"]); } return services; } - public static void MapAspNetHealthChecks(this WebApplication app) + public static WebApplication MapAspNetHealthChecks(this WebApplication app) { - app.MapHealthChecks("/startup", new HealthCheckOptions + app.MapHealthChecks("/health/startup", new HealthCheckOptions { Predicate = check => check.Tags.Contains("dependencies"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); - app.MapHealthChecks("/liveness", new HealthCheckOptions + app.MapHealthChecks("/health/liveness", new HealthCheckOptions { Predicate = check => check.Tags.Contains("self"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); - app.MapHealthChecks("/readiness", new HealthCheckOptions + app.MapHealthChecks("/health/readiness", new HealthCheckOptions { Predicate = check => check.Tags.Contains("critical"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse @@ -74,5 +59,11 @@ public static void MapAspNetHealthChecks(this WebApplication app) Predicate = check => check.Tags.Contains("dependencies"), ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); + app.MapHealthChecks("/health/deep", new HealthCheckOptions + { + Predicate = check => check.Tags.Contains("dependencies") || check.Tags.Contains("external"), + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + return app; } } diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index d19e10680..14c9dbac9 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -28,12 +28,6 @@ public async Task CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { - if (_endpoints.Count == 0) - { - _logger.LogWarning("No endpoints provided."); - return HealthCheckResult.Unhealthy("No endpoints are configured."); - } - var client = _httpClientFactory.CreateClient("HealthCheckClient"); var unhealthyEndpoints = new List(); From e282c7635cf6468ea2db5e5ab3497ee95c7c16f3 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 14:11:42 +0200 Subject: [PATCH 41/49] redo options --- src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 16 ++++++++-------- .../HealthCheckExtensions.cs | 2 +- .../HealthChecks/EndpointsHealthCheck.cs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 4e963f4d2..f0e8ed1db 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -24,6 +24,7 @@ using NSwag; using Serilog; using Digdir.Library.Utils.AspNet; +using static Digdir.Library.Utils.AspNet.HealthCheckExtensions; // Using two-stage initialization to catch startup errors. Log.Logger = new LoggerConfiguration() @@ -129,17 +130,16 @@ static void BuildAndRun(string[] args) // Auth .AddDialogportenAuthentication(builder.Configuration) - .AddAuthorization() - // options.WellKnownEndpointsConfigurationSectionPath = "WebApi:Authentication:JwtBearerTokenSchemas"; - // Health checks with configuration - .AddAspNetHealthChecks(builder.Configuration.GetSection("AspNetHealthChecks").Get()); + .AddAuthorization(); // Retrieve JWT bearer token schema URLs from configuration - var jwtBearerTokenSchemas = builder.Configuration - .GetSection("WebApi:Authentication:JwtBearerTokenSchemas") - .Get>(); + var authSettings = builder.Configuration + .GetSection("WebApi") + .Get(); - var wellKnownUrls = jwtBearerTokenSchemas? + var wellKnownUrls = authSettings? + .Authentication + .JwtBearerTokenSchemas .Select(schema => schema.WellKnown) .Where(url => !string.IsNullOrEmpty(url)) .ToList() ?? new List(); diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index d960d25bd..1d60689b2 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -25,7 +25,7 @@ public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection s { services.Configure(opts => { - opts.Endpoints = settings.HttpGetEndpointsToCheck; + opts.GetEndpoints = settings.HttpGetEndpointsToCheck; }); healthChecks.AddCheck( diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index 14c9dbac9..6c4cd70f8 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -21,7 +21,7 @@ public EndpointsHealthCheck( { _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _endpoints = options?.Value?.Endpoints ?? throw new ArgumentNullException(nameof(options)); + _endpoints = options?.Value?.GetEndpoints ?? throw new ArgumentNullException(nameof(options)); } public async Task CheckHealthAsync( @@ -61,5 +61,5 @@ public async Task CheckHealthAsync( internal sealed class EndpointsHealthCheckOptions { - public List Endpoints { get; set; } = new(); + public List GetEndpoints { get; set; } = new(); } \ No newline at end of file From 51af7ed59d03991434078f4110374cceeca72bb0 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 14:28:52 +0200 Subject: [PATCH 42/49] cleanup --- .../InfrastructureExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 67924ddd3..3d6a2bfc9 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -223,7 +223,7 @@ private static IServiceCollection AddCustomHealthChecks(this IServiceCollection { client.Timeout = TimeSpan.FromSeconds(5); }) - .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); ; + .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); services.AddHealthChecks() .AddCheck("redis", tags: ["dependencies", "redis"]) From 776cb9d0d8eb46205e166b4c70ac8d6e329d6f61 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 14:29:54 +0200 Subject: [PATCH 43/49] cleanup --- src/Digdir.Domain.Dialogporten.WebApi/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index f0e8ed1db..811868c3d 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -134,7 +134,7 @@ static void BuildAndRun(string[] args) // Retrieve JWT bearer token schema URLs from configuration var authSettings = builder.Configuration - .GetSection("WebApi") + .GetSection(WebApiSettings.SectionName) .Get(); var wellKnownUrls = authSettings? From 49a3b89c016d043da64be575e8f7b2faebf7a804 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 14:34:19 +0200 Subject: [PATCH 44/49] cleanup --- .../HealthCheckExtensions.cs | 39 ++++++------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs index 1d60689b2..6831ac6d5 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs @@ -8,11 +8,16 @@ namespace Digdir.Library.Utils.AspNet; +public sealed class AspNetHealthChecksSettings +{ + public List? HttpGetEndpointsToCheck { get; set; } +} + public static class HealthCheckExtensions { - public class AspNetHealthChecksSettings + private static void MapHealthCheckEndpoint(WebApplication app, string path, Func predicate) { - public List? HttpGetEndpointsToCheck { get; set; } + app.MapHealthChecks(path, new HealthCheckOptions { Predicate = predicate, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); } public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, AspNetHealthChecksSettings settings) @@ -39,31 +44,11 @@ public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection s public static WebApplication MapAspNetHealthChecks(this WebApplication app) { - app.MapHealthChecks("/health/startup", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("dependencies"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/health/liveness", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("self"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/health/readiness", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("critical"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/health", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("dependencies"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - app.MapHealthChecks("/health/deep", new HealthCheckOptions - { - Predicate = check => check.Tags.Contains("dependencies") || check.Tags.Contains("external"), - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); + MapHealthCheckEndpoint(app, "/health/startup", check => check.Tags.Contains("dependencies")); + MapHealthCheckEndpoint(app, "/health/liveness", check => check.Tags.Contains("self")); + MapHealthCheckEndpoint(app, "/health/readiness", check => check.Tags.Contains("critical")); + MapHealthCheckEndpoint(app, "/health", check => check.Tags.Contains("dependencies")); + MapHealthCheckEndpoint(app, "/health/deep", check => check.Tags.Contains("dependencies") || check.Tags.Contains("external")); return app; } } From 89accc82bd41f991c6c3f93c2ebeb3895a790f5e Mon Sep 17 00:00:00 2001 From: Magnus Sandgren <5285192+MagnusSandgren@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:04:46 +0200 Subject: [PATCH 45/49] Some suggestions (#1243) --- Digdir.Domain.Dialogporten.sln | 2 +- .../Program.cs | 41 +++++--------- .../AspNetUtilitiesExtensions.cs | 48 +++++++++++++++++ .../AspNetUtilitiesSettings.cs | 11 ++++ .../HealthCheckExtensions.cs | 54 ------------------- .../HealthChecks/EndpointsHealthCheck.cs | 31 +++++------ 6 files changed, 87 insertions(+), 100 deletions(-) create mode 100644 src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs create mode 100644 src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs delete mode 100644 src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs diff --git a/Digdir.Domain.Dialogporten.sln b/Digdir.Domain.Dialogporten.sln index 03a375142..70f082364 100644 --- a/Digdir.Domain.Dialogporten.sln +++ b/Digdir.Domain.Dialogporten.sln @@ -188,7 +188,7 @@ Global {AF35FFCA-1206-4C08-A003-DA4A1344CCD5} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7} {0900E3CF-F9D8-4B29-957F-484B3B028D6D} = {320B47A0-5EB8-4B6E-8C84-90633A1849CA} {E389C7C8-9610-40AC-86DC-769B1B7DC78E} = {CADB8189-4AA1-4732-844A-C41DBF3EC8B7} - {6A485C65-3613-4A49-A16F-2789119F6F38} = {320B47A0-5EB8-4B6E-8C84-90633A1849CA} + {6A485C65-3613-4A49-A16F-2789119F6F38} = {096E9B69-6783-4446-A895-0B6D7729A0D9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B2FE67FF-7622-4AFB-AD8E-961B6A39D888} diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index 811868c3d..cd7961693 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -24,7 +24,7 @@ using NSwag; using Serilog; using Digdir.Library.Utils.AspNet; -using static Digdir.Library.Utils.AspNet.HealthCheckExtensions; +using Microsoft.Extensions.Options; // Using two-stage initialization to catch startup errors. Log.Logger = new LoggerConfiguration() @@ -127,29 +127,18 @@ static void BuildAndRun(string[] args) .AddControllers(options => options.InputFormatters.Insert(0, JsonPatchInputFormatter.Get())) .AddNewtonsoftJson() .Services + // Add health checks with the retrieved URLs + .AddAspNetHealthChecks((x, y) => x.HealthCheckSettings.HttpGetEndpointsToCheck = y + .GetRequiredService>().Value? + .Authentication? + .JwtBearerTokenSchemas? + .Select(z => z.WellKnown) + .ToList() ?? []) // Auth .AddDialogportenAuthentication(builder.Configuration) .AddAuthorization(); - // Retrieve JWT bearer token schema URLs from configuration - var authSettings = builder.Configuration - .GetSection(WebApiSettings.SectionName) - .Get(); - - var wellKnownUrls = authSettings? - .Authentication - .JwtBearerTokenSchemas - .Select(schema => schema.WellKnown) - .Where(url => !string.IsNullOrEmpty(url)) - .ToList() ?? new List(); - - // Add health checks with the retrieved URLs - builder.Services.AddAspNetHealthChecks(new AspNetHealthChecksSettings - { - HttpGetEndpointsToCheck = wellKnownUrls - }); - if (builder.Environment.IsDevelopment()) { var localDevelopmentSettings = builder.Configuration.GetLocalDevelopmentSettings(); @@ -165,6 +154,9 @@ static void BuildAndRun(string[] args) var app = builder.Build(); + app.MapAspNetHealthChecks() + .MapControllers(); + app.UseHttpsRedirection() .UseSerilogRequestLogging() .UseDefaultExceptionHandler() @@ -173,11 +165,8 @@ static void BuildAndRun(string[] args) .UseAuthorization() .UseServiceOwnerOnBehalfOfPerson() .UseUserTypeValidation() - .UseAzureConfiguration(); - - app.MapAspNetHealthChecks(); - - app.UseAddSwaggerCorsHeader() + .UseAzureConfiguration() + .UseAddSwaggerCorsHeader() .UseSwaggerGen(config => { config.PostProcess = (document, _) => @@ -221,8 +210,6 @@ static void BuildAndRun(string[] args) x.Errors.ResponseBuilder = ErrorResponseBuilderExtensions.ResponseBuilder; }); - app.MapControllers(); - app.Run(); } @@ -238,4 +225,4 @@ static void IgnoreEmptyCollections(JsonTypeInfo typeInfo) } // ReSharper disable once ClassNeverInstantiated.Global -public sealed partial class Program; \ No newline at end of file +public sealed partial class Program; diff --git a/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs new file mode 100644 index 000000000..aa3f52ca4 --- /dev/null +++ b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesExtensions.cs @@ -0,0 +1,48 @@ +using Digdir.Library.Utils.AspNet.HealthChecks; +using HealthChecks.UI.Client; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; + +namespace Digdir.Library.Utils.AspNet; + +public static class AspNetUtilitiesExtensions +{ + public static IServiceCollection AddAspNetHealthChecks( + this IServiceCollection services, + Action? configure = null) + => services.AddAspNetHealthChecks((x, _) => configure?.Invoke(x)); + + public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, Action? configure = null) + { + var optionsBuilder = services.AddOptions(); + + if (configure is not null) + { + optionsBuilder.Configure(configure); + } + + return services + .AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]) + .AddCheck( + "Endpoints", + failureStatus: HealthStatus.Unhealthy, + tags: ["external"]) + .Services; + } + + public static WebApplication MapAspNetHealthChecks(this WebApplication app) => + app.MapHealthCheckEndpoint("/health/startup", check => check.Tags.Contains("dependencies")) + .MapHealthCheckEndpoint("/health/liveness", check => check.Tags.Contains("self")) + .MapHealthCheckEndpoint("/health/readiness", check => check.Tags.Contains("critical")) + .MapHealthCheckEndpoint("/health", check => check.Tags.Contains("dependencies")) + .MapHealthCheckEndpoint("/health/deep", check => check.Tags.Contains("dependencies") || check.Tags.Contains("external")); + + private static WebApplication MapHealthCheckEndpoint(this WebApplication app, string path, Func predicate) + { + app.MapHealthChecks(path, new HealthCheckOptions { Predicate = predicate, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); + return app; + } +} diff --git a/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs new file mode 100644 index 000000000..f8e2f7fdb --- /dev/null +++ b/src/Digdir.Library.Utils.AspNet/AspNetUtilitiesSettings.cs @@ -0,0 +1,11 @@ +namespace Digdir.Library.Utils.AspNet; + +public sealed class AspNetUtilitiesSettings +{ + public HealthCheckSettings HealthCheckSettings { get; set; } = new(); +} + +public sealed class HealthCheckSettings +{ + public List HttpGetEndpointsToCheck { get; set; } = []; +} diff --git a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs b/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs deleted file mode 100644 index 6831ac6d5..000000000 --- a/src/Digdir.Library.Utils.AspNet/HealthCheckExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Digdir.Library.Utils.AspNet.HealthChecks; -using HealthChecks.UI.Client; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Diagnostics.HealthChecks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; - -namespace Digdir.Library.Utils.AspNet; - -public sealed class AspNetHealthChecksSettings -{ - public List? HttpGetEndpointsToCheck { get; set; } -} - -public static class HealthCheckExtensions -{ - private static void MapHealthCheckEndpoint(WebApplication app, string path, Func predicate) - { - app.MapHealthChecks(path, new HealthCheckOptions { Predicate = predicate, ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); - } - - public static IServiceCollection AddAspNetHealthChecks(this IServiceCollection services, AspNetHealthChecksSettings settings) - { - var healthChecks = services.AddHealthChecks(); - - healthChecks.AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["self"]); - - if (settings.HttpGetEndpointsToCheck != null && settings.HttpGetEndpointsToCheck.Count > 0) - { - services.Configure(opts => - { - opts.GetEndpoints = settings.HttpGetEndpointsToCheck; - }); - - healthChecks.AddCheck( - "Endpoints", - failureStatus: HealthStatus.Unhealthy, - tags: ["external"]); - } - - return services; - } - - public static WebApplication MapAspNetHealthChecks(this WebApplication app) - { - MapHealthCheckEndpoint(app, "/health/startup", check => check.Tags.Contains("dependencies")); - MapHealthCheckEndpoint(app, "/health/liveness", check => check.Tags.Contains("self")); - MapHealthCheckEndpoint(app, "/health/readiness", check => check.Tags.Contains("critical")); - MapHealthCheckEndpoint(app, "/health", check => check.Tags.Contains("dependencies")); - MapHealthCheckEndpoint(app, "/health/deep", check => check.Tags.Contains("dependencies") || check.Tags.Contains("external")); - return app; - } -} diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index 6c4cd70f8..19ca7e4e9 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -1,7 +1,3 @@ -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -17,17 +13,18 @@ internal sealed class EndpointsHealthCheck : IHealthCheck public EndpointsHealthCheck( IHttpClientFactory httpClientFactory, ILogger logger, - IOptions options) + IOptions options) { _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _endpoints = options?.Value?.GetEndpoints ?? throw new ArgumentNullException(nameof(options)); + _endpoints = options.Value.HealthCheckSettings.HttpGetEndpointsToCheck; } public async Task CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { + // TODO: Denne har en sterk avhengighet på infrastruktur registreringen. Fiks var client = _httpClientFactory.CreateClient("HealthCheckClient"); var unhealthyEndpoints = new List(); @@ -35,12 +32,15 @@ public async Task CheckHealthAsync( { try { + // TODO: Kan kanskje paralelliseres? Trengs sannsynligvis ikke... var response = await client.GetAsync(url, cancellationToken); - if (!response.IsSuccessStatusCode) + if (response.IsSuccessStatusCode) { - _logger.LogWarning("Health check failed for endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); - unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); + continue; } + + _logger.LogWarning("Health check failed for endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); + unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } catch (Exception ex) { @@ -49,17 +49,12 @@ public async Task CheckHealthAsync( } } - if (unhealthyEndpoints.Count > 0) + if (unhealthyEndpoints.Count <= 0) { - var description = $"The following endpoints are unhealthy: {string.Join(", ", unhealthyEndpoints)}"; - return HealthCheckResult.Unhealthy(description); + return HealthCheckResult.Healthy("All endpoints are healthy."); } - return HealthCheckResult.Healthy("All endpoints are healthy."); + var description = $"The following endpoints are unhealthy: {string.Join(", ", unhealthyEndpoints)}"; + return HealthCheckResult.Unhealthy(description); } } - -internal sealed class EndpointsHealthCheckOptions -{ - public List GetEndpoints { get; set; } = new(); -} \ No newline at end of file From abcf9318763145e39a68a441d8c91d82c3de8f3f Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 16:32:10 +0200 Subject: [PATCH 46/49] parallelize --- .../HealthChecks/EndpointsHealthCheck.cs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index 19ca7e4e9..6a1945bd9 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using System.Collections.Concurrent; namespace Digdir.Library.Utils.AspNet.HealthChecks; @@ -25,31 +26,31 @@ public async Task CheckHealthAsync( CancellationToken cancellationToken = default) { // TODO: Denne har en sterk avhengighet på infrastruktur registreringen. Fiks + // Parallelize the requests var client = _httpClientFactory.CreateClient("HealthCheckClient"); - var unhealthyEndpoints = new List(); + var unhealthyEndpoints = new ConcurrentBag(); - foreach (var url in _endpoints) + var tasks = _endpoints.Select(async url => { try { - // TODO: Kan kanskje paralelliseres? Trengs sannsynligvis ikke... var response = await client.GetAsync(url, cancellationToken); - if (response.IsSuccessStatusCode) + if (!response.IsSuccessStatusCode) { - continue; + _logger.LogWarning("Health check failed for endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); + unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } - - _logger.LogWarning("Health check failed for endpoint: {Url}. Status Code: {StatusCode}", url, response.StatusCode); - unhealthyEndpoints.Add($"{url} (Status Code: {response.StatusCode})"); } catch (Exception ex) { _logger.LogError(ex, "Exception occurred while checking endpoint: {Url}", url); unhealthyEndpoints.Add($"{url} (Exception: {ex.GetType().Name})"); } - } + }); + + await Task.WhenAll(tasks); - if (unhealthyEndpoints.Count <= 0) + if (unhealthyEndpoints.IsEmpty) { return HealthCheckResult.Healthy("All endpoints are healthy."); } From 284cd1766805e1828efe6791eb7b30d34c85442b Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Mon, 7 Oct 2024 16:44:36 +0200 Subject: [PATCH 47/49] cleanup --- .../InfrastructureExtensions.cs | 7 ------- .../HealthChecks/EndpointsHealthCheck.cs | 1 - 2 files changed, 8 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs index 3d6a2bfc9..be49b2f21 100644 --- a/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs +++ b/src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs @@ -218,13 +218,6 @@ public static IServiceCollection AddInfrastructure(this IServiceCollection servi private static IServiceCollection AddCustomHealthChecks(this IServiceCollection services) { - services.AddHttpClient("HealthCheckClient") - .ConfigureHttpClient(client => - { - client.Timeout = TimeSpan.FromSeconds(5); - }) - .AddPolicyHandlerFromRegistry(PollyPolicy.DefaultHttpRetryPolicy); - services.AddHealthChecks() .AddCheck("redis", tags: ["dependencies", "redis"]) .AddDbContextCheck("postgres", tags: ["dependencies", "critical"]); diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index 6a1945bd9..a4f815a60 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -26,7 +26,6 @@ public async Task CheckHealthAsync( CancellationToken cancellationToken = default) { // TODO: Denne har en sterk avhengighet på infrastruktur registreringen. Fiks - // Parallelize the requests var client = _httpClientFactory.CreateClient("HealthCheckClient"); var unhealthyEndpoints = new ConcurrentBag(); From 353138e26f7869b5327e7f88b50f337f8e883301 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Tue, 8 Oct 2024 10:18:15 +0200 Subject: [PATCH 48/49] cleanup --- .../Program.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs index cd7961693..1367bcd63 100644 --- a/src/Digdir.Domain.Dialogporten.WebApi/Program.cs +++ b/src/Digdir.Domain.Dialogporten.WebApi/Program.cs @@ -166,6 +166,23 @@ static void BuildAndRun(string[] args) .UseServiceOwnerOnBehalfOfPerson() .UseUserTypeValidation() .UseAzureConfiguration() + .UseFastEndpoints(x => + { + x.Endpoints.RoutePrefix = "api"; + x.Versioning.Prefix = "v"; + x.Versioning.PrependToRoute = true; + x.Versioning.DefaultVersion = 1; + x.Serializer.Options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + // Do not serialize empty collections + x.Serializer.Options.TypeInfoResolver = new DefaultJsonTypeInfoResolver + { + Modifiers = { IgnoreEmptyCollections } + }; + x.Serializer.Options.Converters.Add(new JsonStringEnumConverter()); + x.Serializer.Options.Converters.Add(new UtcDateTimeOffsetConverter()); + x.Serializer.Options.Converters.Add(new DateTimeNotSupportedConverter()); + x.Errors.ResponseBuilder = ErrorResponseBuilderExtensions.ResponseBuilder; + }) .UseAddSwaggerCorsHeader() .UseSwaggerGen(config => { @@ -191,23 +208,6 @@ static void BuildAndRun(string[] args) // We have to add dialogporten here to get the correct base url for swagger.json in the APIM. Should not be done for development var dialogPrefix = builder.Environment.IsDevelopment() ? "" : "/dialogporten"; uiConfig.DocumentPath = dialogPrefix + "/swagger/{documentName}/swagger.json"; - }) - .UseFastEndpoints(x => - { - x.Endpoints.RoutePrefix = "api"; - x.Versioning.Prefix = "v"; - x.Versioning.PrependToRoute = true; - x.Versioning.DefaultVersion = 1; - x.Serializer.Options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; - // Do not serialize empty collections - x.Serializer.Options.TypeInfoResolver = new DefaultJsonTypeInfoResolver - { - Modifiers = { IgnoreEmptyCollections } - }; - x.Serializer.Options.Converters.Add(new JsonStringEnumConverter()); - x.Serializer.Options.Converters.Add(new UtcDateTimeOffsetConverter()); - x.Serializer.Options.Converters.Add(new DateTimeNotSupportedConverter()); - x.Errors.ResponseBuilder = ErrorResponseBuilderExtensions.ResponseBuilder; }); app.Run(); From de44087c48b574b0df32e708ddaad43ef4ec8029 Mon Sep 17 00:00:00 2001 From: Are Almaas Date: Tue, 8 Oct 2024 10:36:52 +0200 Subject: [PATCH 49/49] cleanup --- .../HealthChecks/EndpointsHealthCheck.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs index a4f815a60..98e7567ee 100644 --- a/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs +++ b/src/Digdir.Library.Utils.AspNet/HealthChecks/EndpointsHealthCheck.cs @@ -25,8 +25,7 @@ public async Task CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { - // TODO: Denne har en sterk avhengighet på infrastruktur registreringen. Fiks - var client = _httpClientFactory.CreateClient("HealthCheckClient"); + var client = _httpClientFactory.CreateClient(); var unhealthyEndpoints = new ConcurrentBag(); var tasks = _endpoints.Select(async url =>