-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Description
Journal health checks are not registered when using .WithHealthCheck() without adding event adapters. This is due to an early return in AkkaPersistenceJournalBuilder.Build() that exits before health check registration occurs.
Reproduction
protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
{
var journalOptions = new SqlJournalOptions(true)
{
ConnectionString = "...",
ProviderName = ProviderName.SQLite
};
// ❌ Health check NOT registered - no event adapters added
builder.WithJournal(
journalOptions,
journal => journal.WithHealthCheck());
}
// Result: No journal health check appears in HealthCheckServiceExpected Behavior
Health checks should be registered regardless of whether event adapters are configured. These are independent features.
Actual Behavior
Health check is silently ignored. Only appears if you also add an event adapter:
// ✅ Health check IS registered - event adapter added
builder.WithJournal(
journalOptions,
journal => journal
.AddWriteEventAdapter<MyAdapter>("adapter", [typeof(MyEvent)])
.WithHealthCheck());Root Cause
File: src/Akka.Persistence.Hosting/AkkaPersistenceHostingExtensions.cs
Method: AkkaPersistenceJournalBuilder.Build() (lines 113-133)
internal void Build()
{
// useless configuration - don't bother.
if (Adapters.Count == 0 || Bindings.Count == 0)
return; // ← EXITS EARLY, skips health check registration!
var adapters = new StringBuilder()
.Append($"akka.persistence.journal.{JournalId}").Append("{");
AppendAdapters(adapters);
adapters.AppendLine("}");
var finalHocon = ConfigurationFactory.ParseString(adapters.ToString())
.WithFallback(Persistence.DefaultConfig());
Builder.AddHocon(finalHocon, HoconAddMode.Prepend);
// add the health checks if specified
if(HealthCheckRegistration != null)
Builder.WithHealthCheck(HealthCheckRegistration); // ← NEVER REACHED!
}The early return at line 116 exits before health check registration at line 132.
Proposed Fix
Move health check registration before the early return:
internal void Build()
{
// add the health checks if specified - do this FIRST
if(HealthCheckRegistration != null)
Builder.WithHealthCheck(HealthCheckRegistration);
// useless configuration - don't bother with adapters if none configured
if (Adapters.Count == 0 || Bindings.Count == 0)
return;
var adapters = new StringBuilder()
.Append($"akka.persistence.journal.{JournalId}").Append("{");
AppendAdapters(adapters);
adapters.AppendLine("}");
var finalHocon = ConfigurationFactory.ParseString(adapters.ToString())
.WithFallback(Persistence.DefaultConfig());
Builder.AddHocon(finalHocon, HoconAddMode.Prepend);
}This ensures health checks are registered even when no event adapters are configured.
Impact
Medium-High: Users expecting health checks to work will find they're silently not registered unless they also happen to configure event adapters. This creates a confusing and non-obvious dependency between two unrelated features.
Workaround
Always add at least one event adapter (even a no-op) when using health checks:
builder.WithJournal(
journalOptions,
journal => journal
.AddWriteEventAdapter<IdentityAdapter>("noop", []) // Workaround
.WithHealthCheck());Note on Snapshot Stores
This bug does NOT affect snapshot stores because AkkaPersistenceSnapshotBuilder.Build() doesn't have the same early return pattern - it always registers health checks.
Discovery
This issue was discovered while refactoring Akka.Persistence.Sql.Hosting to use the unified API in PR akkadotnet/Akka.Persistence.Sql#549. The refactoring exposed this edge case where health checks are registered for snapshot stores but not journals when no event adapters are present.
Test Coverage
The existing test JournalAndSnapshotWithBuildersSpec (UnifiedApiSpecs.cs:224-286) doesn't catch this bug because it adds an event adapter before calling .WithHealthCheck():
journal => journal
.AddWriteEventAdapter<UnifiedApiTestResources.TestWriteAdapter>("adapter",
[typeof(UnifiedApiTestResources.TestEvent)])
.WithHealthCheck(), // Works because adapter was added firstRecommended test: Add a test that calls .WithHealthCheck() WITHOUT adding event adapters to ensure health checks work independently.