Skip to content

AOT: module serializer tables for the Cluster contrib family (#8626, part 3b) - #8669

Merged
Aaronontheweb merged 5 commits into
akkadotnet:devfrom
Aaronontheweb:feature/aot-m2-3b-cluster-contrib-serializers
Sep 30, 2026
Merged

Aaronontheweb merged 5 commits into
akkadotnet:devfrom
Aaronontheweb:feature/aot-m2-3b-cluster-contrib-serializers

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Part 3b of #8626. Follows #8658 and part 3a (#8666)'s module-table pattern for the four Cluster contrib modules: Tools, Sharding, DistributedData and Metrics. Split from 3a to keep each PR reviewable.

Note: this PR and #8666 both add lines to ModuleSerializerTable.Default's map in src/core/Akka/Serialization/ModuleSerializers.cs. They'll conflict trivially on merge -- whichever lands second just needs to keep both sets of map entries.

Changes

  • ToolsSerializers (Akka.Cluster.Tools) covers all three of Tools' reference.conf files in one table: ClusterClientMessageSerializer (Client, id 15), DistributedPubSubMessageSerializer (PublishSubscribe, id 9), ClusterSingletonMessageSerializer (Singleton, id 14). It lives at the top Akka.Cluster.Tools namespace, not under a feature's own Serialization sub-namespace, since it spans all three.
  • ShardingSerializers (Akka.Cluster.Sharding.Serialization) covers ClusterShardingMessageSerializer (id 13).
  • DistributedDataSerializers (Akka.DistributedData.Serialization) covers ReplicatedDataSerializer (id 11) and ReplicatorMessageSerializer (id 12).
  • MetricsSerializers (Akka.Cluster.Metrics.Serialization) covers ClusterMetricsMessageSerializer (id 10) and its five bound types.
  • Core's module map gets four more entries: "Akka.Cluster.Tools", "Akka.Cluster.Sharding", "Akka.DistributedData", "Akka.Cluster.Metrics", each passing a type-name literal to Load.

Constructor choices

All seven serializers here have exactly one constructor, and none of the four modules' shipped configs has a serialization-settings block for any of these aliases, so every factory calls the class's only constructor directly:

Module Alias Class Constructor Why
Tools (Client) akka-cluster-client ClusterClientMessageSerializer (system) only ctor; no settings block
Tools (PublishSubscribe) akka-pubsub DistributedPubSubMessageSerializer (system) only ctor; no settings block
Tools (Singleton) akka-singleton ClusterSingletonMessageSerializer (system) only ctor; no settings block
Sharding akka-sharding ClusterShardingMessageSerializer (system) only ctor; no settings block
DistributedData akka-replicated-data ReplicatedDataSerializer (system) only ctor; no settings block
DistributedData akka-data-replication ReplicatorMessageSerializer (system) only ctor; no settings block
Metrics akka-cluster-metrics ClusterMetricsMessageSerializer (system) only ctor; no settings block

IVT

Akka core did not grant Akka.Cluster.Metrics access to its internals (every other module in this family already had it), and the table must subclass the internal ModuleSerializers, so src/core/Akka/Properties/AssemblyInfo.cs gets one new InternalsVisibleTo("Akka.Cluster.Metrics"). CoreAPISpec.ApproveCore.{DotNet,Net}.verified.txt are updated to match (one line each). No other IVT changes -- Tools, Sharding and DistributedData already had core access, as did their own Tests projects; Tools' own assembly already grants its Tests project access to ToolsSerializers, and likewise for Sharding/DistributedData/Metrics.

Behavior with the switch on (recorded in this PR's Breaking changes section below)

Same shape as #8658 and 3a, measured against these four modules:

  • A serialization-settings.<alias> block for any of these seven serializers now builds it instead of throwing MissingMethodException.
  • Constructor exceptions are no longer wrapped in TargetInvocationException.
  • With the switch off, every row across all four modules now resolves instead of throwing ConfigurationException.

Tests

One short spec per module, each in a DynamicTypeLoadingCollection (non-parallel), reusing ModuleSerializerSpecs (Akka.Tests.Shared.Internals.Xunit3):

  • ShardingSerializersSpec (Akka.Cluster.Sharding.Tests) and MetricsSerializersSpec (Akka.Cluster.Metrics.Tests): both projects already have an InternalsVisibleTo grant from Akka core, so these specs are the full shape -- table-matches-config (both directions), Akka.Hosting AQN spelling, an application.conf override, a reflection-only baseline (needs the internal ModuleSerializerTable constructor), and switch-off ids/classes.
  • ToolsSerializersSpec (Akka.Cluster.Tools.Tests) and DistributedDataSerializersSpec (Akka.DistributedData.Tests): neither project has that grant. Serialization.GetSerializerById is internal too, so these two specs check bound types by class via the public FindSerializerForType instead of by wire id, and keep a hand-written mirror of each table's serializer-type list (SerializerTypes) rather than reading table.Serializers live, since the internal ModuleSerializer record itself isn't visible without that grant. Both still exercise the real production table through AssertBuildsWithoutWarning, which builds an actual Serialization from the default module map.
  • Every test project referenced Akka.Tests.Shared.Internals.Xunit3 already except Akka.Cluster.Metrics.Tests, which gets that ProjectReference added.
  • All new specs pass on 3 repeated runs.

Mutation check (reverted before this PR)

Removing ClusterSingletonMessageSerializer from ToolsSerializers.Serializers fails 3 of ToolsSerializersSpec's 4 facts (the AQN check and the switch-off build/class checks -- constructing Serialization for that config now throws ConfigurationException for the akka-singleton alias).

Validation

  • dotnet build -c Release -warnaserror: Akka, Akka.Cluster.Tools, Akka.Cluster.Sharding, Akka.DistributedData, Akka.Cluster.Metrics, and their four test projects -- 0 warnings.
  • Each new spec passes on 3 repeated runs (Tools 4 facts, Sharding 5, DistributedData 4, Metrics 5).
  • dotnet test src/core/Akka.Tests -c Release -f net10.0 --filter "FullyQualifiedName~Serialization": 128 passed.
  • Akka.API.Tests: 23 passed, with the two verified-file updates above.

Breaking changes

Component Type Change Migration
Akka.Cluster.Tools / Akka.Cluster.Sharding / Akka.DistributedData / Akka.Cluster.Metrics (serialization) Behavior Each module's reference.conf serializers (Tools: ClusterClientMessageSerializer, DistributedPubSubMessageSerializer, ClusterSingletonMessageSerializer across its three feature configs; Sharding: ClusterShardingMessageSerializer; DistributedData: ReplicatedDataSerializer, ReplicatorMessageSerializer; Metrics: ClusterMetricsMessageSerializer) are now built from an internal module table ahead of reflection, with Akka.DynamicTypeLoading on as well as off. Every one of these seven classes has a single (system) constructor and no serialization-settings block in its shipped config, so each factory calls that constructor directly. With the switch on, two things differ: (1) a serialization-settings.<alias> block for any of these seven serializers now builds it instead of throwing MissingMethodException; (2) an exception from one of these constructors is no longer wrapped in TargetInvocationException. With the switch off, every row here now resolves instead of throwing ConfigurationException. Same mechanism as #8658. None. Code that caught MissingMethodException or TargetInvocationException around ActorSystem.Create for these 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.)

…net#8626, part 3b)

Adds ToolsSerializers (Akka.Cluster.Tools, covering all three of Client,
PublishSubscribe and Singleton), ShardingSerializers (Akka.Cluster.Sharding),
DistributedDataSerializers (Akka.DistributedData) and MetricsSerializers
(Akka.Cluster.Metrics) to core's module map. Every serializer in these four
modules has a single (system) constructor and no serialization-settings
block in its shipped config, so each factory calls that constructor
directly.

Akka.Cluster.Metrics gets a new InternalsVisibleTo grant from Akka core,
needed for its table to subclass the internal ModuleSerializers; the API
approval snapshots are updated to match.

Akka.Cluster.Tools.Tests and Akka.DistributedData.Tests have no
InternalsVisibleTo grant from Akka core, so their specs skip the
reflection-only baseline and keep a hand-written mirror of each table's
serializer-type list instead of reading it live.
@Aaronontheweb Aaronontheweb added serialization AOT Ahead-of-Time (AOT) Compilation labels Sep 30, 2026
…im reflection baselines

- Grant Akka core InternalsVisibleTo to Akka.Cluster.Tools.Tests and
  Akka.DistributedData.Tests so their specs can see the internal
  ModuleSerializer record and Serialization.GetSerializerById. Update
  both CoreAPISpec.ApproveCore.{DotNet,Net}.verified.txt.
- ToolsSerializersSpec and DistributedDataSerializersSpec now feed the
  real table (table.Serializers.Select(s => s.Type)) into the parity
  helper instead of a hand-kept mirror list, and check wire ids (15, 9,
  14, 11, 12) the way the other specs do. Verified with a mutation: an
  extra bogus serializer row in either table fails the parity check,
  then reverted.
- Drop the reflection-only baseline from ShardingSerializersSpec and
  MetricsSerializersSpec, and their now-unused Build/NoModules/
  SwitchName helpers; the switch-off id test already covers these
  single-constructor, settings-free factories.
- Remove the redundant Akka.Tests.Shared.Internals.Xunit3
  ProjectReference from Akka.Cluster.Metrics.Tests.csproj; it already
  arrives transitively through Akka.Cluster.Tests.
- Ledger: drop the InternalsVisibleTo aside (not breaking) and the
  unmeasured versioned-name claim from the row.

@Aaronontheweb Aaronontheweb left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

…cluster-contrib-serializers

# Conflicts:
#	BREAKING_CHANGES_V1.6.md
#	src/core/Akka/Serialization/ModuleSerializers.cs
…1.6.md edit (batch PR will update the ledger)
@Aaronontheweb
Aaronontheweb merged commit 37ada27 into akkadotnet:dev Sep 30, 2026
11 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AOT Ahead-of-Time (AOT) Compilation serialization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant