-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Summary
JournalOptions.Adapters property should be deprecated in favor of the callback pattern introduced in PR#662. Having two competing ways to configure event adapters is confusing and inconsistent with the health check API.
Problem
Currently there are two ways to configure event adapters:
Pattern 1: Adapters Property (Legacy)
var journalOptions = new SqlJournalOptions(true)
{
Adapters = new AkkaPersistenceJournalBuilder("sql", builder),
// ... other options
};
journalOptions.Adapters.AddWriteEventAdapter<ColorFruitTagger>("tagger", [typeof(string)]);
builder.WithJournal(journalOptions);Pattern 2: Callback (Unified API from PR#662)
var journalOptions = new SqlJournalOptions(true)
{
// ... options only
};
builder.WithJournal(
journalOptions,
journal => journal.AddWriteEventAdapter<ColorFruitTagger>("tagger", [typeof(string)]));Design Flaws
- Competing Patterns - No clear guidance on which pattern to use
- Inconsistent with Health Checks - Health checks ONLY support the callback pattern
- Both Can Be Used Simultaneously - Unclear merge semantics when both are provided
- Dangerous Default - Property initialized with dummy builder:
new AkkaPersistenceJournalBuilder("", null!)(potential NRE) - Violates DRY - Two mechanisms for the same functionality
Code Locations
JournalOptions.cs (line 78):
public AkkaPersistenceJournalBuilder Adapters { get; set; } = new ("", null!);AkkaPersistenceHostingExtensions.cs (lines 262-271):
// Line 262: Applies adapters from property
builder.AddHocon(journalOptions.ToConfig(), HoconAddMode.Prepend);
// Lines 266-271: ALSO applies adapters from callback
if (configureBuilder != null)
{
var jBuilder = new AkkaPersistenceJournalBuilder(journalOptions.Identifier, builder);
configureBuilder(jBuilder);
jBuilder.Build();
}Impact on Users
Current behavior (when both are used):
var journalOptions = new SqlJournalOptions(true)
{
Adapters = new AkkaPersistenceJournalBuilder("sql", builder)
};
journalOptions.Adapters.AddWriteEventAdapter<AdapterA>(...);
builder.WithJournal(
journalOptions,
journal => journal.AddWriteEventAdapter<AdapterB>(...)); // ← Both A and B get registered!HOCON silently merges both configurations. This is:
- ❌ Not documented
- ❌ Not obvious
- ❌ Hard to debug
Proposed Solution
Phase 1: Deprecation (v1.5)
- Mark property as obsolete:
[Obsolete("Use the configureBuilder callback parameter in WithJournal() instead. This property will be removed in v1.6.")]
public AkkaPersistenceJournalBuilder Adapters { get; set; } = new ("", null!);- Add analyzer warning when property is set
- Update documentation to show callback pattern only
- Add migration guide to release notes
Phase 2: Removal (v1.6)
Remove the property entirely, forcing users to use the callback pattern.
Benefits
- ✅ Single Pattern - One clear way to configure adapters
- ✅ Consistency - Same pattern as health checks
- ✅ Safety - Callback guarantees
.Build()is called - ✅ Clarity - No confusion about which pattern to use
- ✅ Cleaner API - Options objects contain only configuration data
Migration Path
Before (deprecated):
var journalOptions = new SqlJournalOptions(true)
{
Adapters = new AkkaPersistenceJournalBuilder("sql", builder),
ConnectionString = "...",
};
journalOptions.Adapters.AddWriteEventAdapter<Foo>("foo", [typeof(Bar)]);
builder.WithJournal(journalOptions);After (recommended):
var journalOptions = new SqlJournalOptions(true)
{
ConnectionString = "...",
// No Adapters property
};
builder.WithJournal(
journalOptions,
journal => journal.AddWriteEventAdapter<Foo>("foo", [typeof(Bar)]));Related Issues
This issue was discovered during refactoring in Akka.Persistence.Sql#549, where the unified API was adopted to fix health check registration.
Recommendation
Deprecate in v1.5, remove in v1.6. This gives users plenty of time to migrate while cleaning up the API surface.