Skip to content

AOT: module serializer table for Akka.Persistence (#8626, part 4) - #8695

Merged
Aaronontheweb merged 1 commit into
akkadotnet:devfrom
Aaronontheweb:feature/aot-m2-4-persistence-serializers
Sep 30, 2026
Merged

Aaronontheweb merged 1 commit into
akkadotnet:devfrom
Aaronontheweb:feature/aot-m2-4-persistence-serializers

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Member

Part 4 of #8626. Follows #8658's module-table pattern (Akka.Cluster, part 3a; the Cluster contrib family, part 3b) for Akka.Persistence.

Changes

  • PersistenceSerializers (Akka.Persistence.Serialization) is Persistence's first ModuleSerializers table. It covers every serializers and serialization-bindings row persistence.conf adds to akka.actor: PersistenceMessageSerializer (id 7, alias akka-persistence-message) and PersistenceSnapshotSerializer (id 8, alias akka-persistence-snapshot).
  • Core's module map gets one more entry: "Akka.Persistence", passing a type-name literal to Load.
  • Bound types: IMessage and Snapshot, exactly as persistence.conf's two binding rows name them.

Constructor choices

Both classes have exactly one constructor, and persistence.conf has no serialization-settings block for either alias, so the factory calls the class's only constructor directly:

Alias Class Constructor Why
akka-persistence-message PersistenceMessageSerializer (system) only ctor; no settings block
akka-persistence-snapshot PersistenceSnapshotSerializer (system) only ctor; no settings block

No public API changes (verified by Akka.API.Tests, 23 passed). No IVT changes: Akka core already grants Akka.Persistence and Akka.Persistence.Tests access to its internals, and Akka.Persistence already grants its own Tests project access to PersistenceSerializers.

Neither serializer overrides Identifier in code (#8694, which adds that, isn't merged yet) -- both still resolve their id through akka.actor.serialization-identifiers, so this table doesn't depend on it.

Behavior with the switch on (see Breaking changes below)

Same shape as #8658/#8666, measured against this module:

  • A serialization-settings.<alias> block for either serializer now builds it instead of throwing MissingMethodException, since neither constructor takes a Config.
  • Constructor exceptions are no longer wrapped in TargetInvocationException.
  • With the switch off, both rows now resolve instead of throwing ConfigurationException.

Tests

PersistenceSerializersSpec (Akka.Persistence.Tests) runs in a DynamicTypeLoadingCollection (non-parallel) and derives from AkkaSpec with ITestOutputHelper, reusing ModuleSerializerSpecs (Akka.Tests.Shared.Internals.Xunit3) for the shared checks:

  • Table matches config, both directions: AssertTableMatchesConfig -- the table's Serializers/BoundTypes name exactly the types persistence.conf's rows name.
  • Akka.Hosting spelling: AssertHostingSpellingResolves -- every row, respelled as an AssemblyQualifiedName, still resolves with the switch off.
  • Switch off, default config: AssertBuildsWithoutWarning -- builds without a warning; ids 7 and 8 map to the right classes.
  • Reflection baseline (own to this spec, needs the internal table): with the switch on, the factory-built serializer matches what reflection builds, in class and Identifier, for bound samples AtLeastOnceDeliverySnapshot (an IMessage implementer) and Snapshot.
  • Override: an application.conf binding (Snapshot = bytes) takes effect and leaves the other alias alone.

All 5 facts pass on 3 repeated runs. The existing Persistence serializer round-trip tests still pass: dotnet test src/core/Akka.Persistence.Tests -c Release -f net10.0 --filter "FullyQualifiedName~Serializ" -- 18 passed.

Mutation checks (done locally, reverted before this PR)

  • Removing Snapshot from BoundTypes fails all 5 facts (table-matches-config, and every other check that depends on resolving Snapshot).
  • Adding a bogus bound type (typeof(string)) fails 2 of 5 facts (both directions of the table-matches-config check).

Validation

  • dotnet build -c Release -warnaserror: Akka, Akka.Persistence, Akka.Persistence.Tests, Akka.API.Tests -- 0 warnings.
  • PersistenceSerializersSpec passes on 3 repeated runs.
  • Akka.API.Tests: 23 passed, no API changes.

This completes the per-module serializer tables (#8626) needed before plan PR 3 of #8676.

Breaking changes

Component Type Change Migration
Akka.Persistence (serialization) Behavior persistence.conf's two serializers (PersistenceMessageSerializer, PersistenceSnapshotSerializer) are now built from an internal module table ahead of reflection, with Akka.DynamicTypeLoading on as well as off. Both classes have a single (system) constructor and no serialization-settings block in their shipped config, so each factory calls that constructor directly. With the switch on, two things differ: (1) a serialization-settings.<alias> block for either serializer now builds it instead of throwing MissingMethodException; (2) a constructor exception is no longer wrapped in TargetInvocationException. With the switch off, both rows now resolve instead of throwing ConfigurationException. Same mechanism as #8658. None. Code that caught MissingMethodException or TargetInvocationException around ActorSystem.Create for these two serializers should catch the inner exception type instead.

(The shared BREAKING_CHANGES_V1.6.md ledger itself is not touched by this PR -- it is updated in a separate batch PR.)

…art 4)

Adds PersistenceSerializers, covering persistence.conf's two serializers
(PersistenceMessageSerializer id 7, PersistenceSnapshotSerializer id 8) and
their two bound types (IMessage, Snapshot), to core's module map. Both
classes have a single (system) constructor and neither has a
serialization-settings block in persistence.conf, so the factory calls
that constructor directly for each.

PersistenceSerializersSpec mirrors ClusterSerializersSpec/StreamsSerializersSpec:
parity against persistence.conf in both directions, Akka.Hosting AQN spelling
resolution, an application.conf override, and building under the default
config with the switch off, logging no warning, with ids 7/8 resolving to
the right classes.
@Aaronontheweb Aaronontheweb added akka-persistence AOT Ahead-of-Time (AOT) Compilation labels Sep 30, 2026
@Aaronontheweb
Aaronontheweb merged commit d8d6a4e into akkadotnet:dev Sep 30, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

akka-persistence AOT Ahead-of-Time (AOT) Compilation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant