From 29f43b84e80e68c2e25da766f853fb479c662cf8 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Thu, 2 Oct 2025 08:32:12 -0500 Subject: [PATCH] Fix journal health check registration without event adapters Fixes #666 Journal health checks were not being registered when using .WithHealthCheck() without adding event adapters. This was caused by an early return in AkkaPersistenceJournalBuilder.Build() that exited before health check registration occurred. Changes: - Move health check registration before the early return to ensure health checks are registered regardless of event adapter configuration - Add regression test that verifies health checks work without adapters All 16 persistence hosting tests pass. --- .../UnifiedApiSpecs.cs | 50 +++++++++++++++++++ .../AkkaPersistenceHostingExtensions.cs | 8 +-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/Akka.Persistence.Hosting.Tests/UnifiedApiSpecs.cs b/src/Akka.Persistence.Hosting.Tests/UnifiedApiSpecs.cs index e540483d..c64bd66a 100644 --- a/src/Akka.Persistence.Hosting.Tests/UnifiedApiSpecs.cs +++ b/src/Akka.Persistence.Hosting.Tests/UnifiedApiSpecs.cs @@ -285,6 +285,56 @@ public async Task WithJournalAndSnapshot_with_builders_should_configure_everythi } } +/// +/// Regression test for https://github.com/akkadotnet/Akka.Hosting/issues/666 +/// Ensures journal health checks are registered even without event adapters +/// +public sealed class JournalHealthCheckWithoutAdaptersSpec : Akka.Hosting.TestKit.TestKit +{ + public JournalHealthCheckWithoutAdaptersSpec(ITestOutputHelper output) : base(output: output) + { + } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + base.ConfigureServices(context, services); + services.AddHealthChecks(); + } + + protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider) + { + var journalOptions = new UnifiedApiTestResources.TestJournalOptions { IsDefaultPlugin = true }; + + // Configure journal with health check but WITHOUT any event adapters + // This is the regression case from issue #666 + builder.WithJournal( + journalOptions, + journal => journal.WithHealthCheck()); + } + + [Fact] + public async Task Journal_health_check_should_be_registered_without_event_adapters() + { + // assert - journal plugin configured + var config = Sys.Settings.Config; + config.HasPath("akka.persistence.journal.test-journal") + .Should().BeTrue(); + + // assert - health check is registered even without event adapters + var healthCheckService = Host.Services.GetRequiredService(); + var result = await healthCheckService.CheckHealthAsync(); + + result.Status.Should().Be(HealthStatus.Healthy, + "journal health check should be healthy"); + + // Verify journal health check is present + var journalCheck = result.Entries.FirstOrDefault(e => e.Key.Contains("test-journal")); + journalCheck.Should().NotBeNull("journal health check should be registered even without event adapters"); + journalCheck.Value.Status.Should().Be(HealthStatus.Healthy, + "journal health check should return healthy status"); + } +} + /// /// Test null builder actions work correctly /// diff --git a/src/Akka.Persistence.Hosting/AkkaPersistenceHostingExtensions.cs b/src/Akka.Persistence.Hosting/AkkaPersistenceHostingExtensions.cs index 8713f653..8463b51f 100644 --- a/src/Akka.Persistence.Hosting/AkkaPersistenceHostingExtensions.cs +++ b/src/Akka.Persistence.Hosting/AkkaPersistenceHostingExtensions.cs @@ -112,6 +112,10 @@ private AkkaHealthCheckRegistration AddHealthCheck(string? name, HealthStatus un /// internal void Build() { + // add the health checks if specified - do this FIRST before any early returns + if(HealthCheckRegistration != null) + Builder.WithHealthCheck(HealthCheckRegistration); + // useless configuration - don't bother. if (Adapters.Count == 0 || Bindings.Count == 0) return; @@ -126,10 +130,6 @@ internal void Build() var finalHocon = ConfigurationFactory.ParseString(adapters.ToString()) .WithFallback(Persistence.DefaultConfig()); // add the default config as a fallback Builder.AddHocon(finalHocon, HoconAddMode.Prepend); - - // add the health checks if specified - if(HealthCheckRegistration != null) - Builder.WithHealthCheck(HealthCheckRegistration); } internal void AppendAdapters(StringBuilder sb)