Skip to content

Akka.Hosting: add missing trimming annotations for Native AOT - #8655

Merged
Aaronontheweb merged 2 commits into
akkadotnet:devfrom
Aaronontheweb:fix/hosting-aot-annotations
Sep 28, 2026
Merged

Aaronontheweb merged 2 commits into
akkadotnet:devfrom
Aaronontheweb:fix/hosting-aot-annotations

Conversation

@Aaronontheweb

@Aaronontheweb Aaronontheweb commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Summary

A Native AOT prototype for Akka.Hosting found three call sites where a generic type parameter (or reflected Type) is passed into an API that requires [DynamicallyAccessedMembers], without the matching annotation on the Akka.Hosting side. Under trimming/Native AOT this lets the linker remove constructor reflection metadata the callee actually needs.

  • AddAkka<T> forwards T into IServiceCollection.AddHostedService<T>(), which requires PublicConstructors. Without the annotation, a Native AOT publish removes AkkaHostedService's constructor reflection metadata and host.StartAsync() throws InvalidOperationException: A suitable constructor for type 'Akka.Hosting.AkkaHostedService' could not be located.
  • AkkaConfigurationBuilder.WithHealthCheck<T> forwards T into ActivatorUtilities.GetServiceOrCreateInstance<T>(), same requirement (PublicConstructors).
  • The obsolete LoggerConfigBuilder.LogMessageFormatter setter calls value.GetConstructor([]), which requires PublicConstructors on the Type passed in; WithDefaultLogMessageFormatter<T>() assigns typeof(T) into it, so the same annotation is propagated onto its T.

Grepped Akka.Hosting, Akka.Remote.Hosting, Akka.Cluster.Hosting and Akka.Persistence.Hosting for the same shape (AddHostedService, AddSingleton<TService,TImpl>, ActivatorUtilities, Activator.CreateInstance<T>). The other generic parameters found - ActorRegistry's TKey/TActor, Akka.Cluster.Hosting's per-entity TKey on WithShardRegion/WithSingleton/WithClusterClient/etc., and Akka.Persistence.Hosting's TAdapter - are only ever used as typeof(T) dictionary keys or config values, never passed into a DynamicallyAccessedMembers-requiring API, so none of them need a change. AkkaConfigurationBuilder.AddExtensions()'s Type.GetType(trimmed) for akka.extensions/WithExtension<T> is a separate, already-tracked gap (#8649) and is intentionally left alone here.

Updated the Hosting API approval baseline (CoreAPISpec.ApproveHosting.DotNet.verified.txt) for the new attributes. No BREAKING_CHANGES_V1.6.md row: the annotations are source- and binary-compatible and only show up as IL2091 for callers who run the trim analyzer.

The formatter's backing field carries the same annotation, so its getter doesn't raise IL2078. With EnableTrimAnalyzer=true, Akka.Hosting's only remaining warning is the akka.extensions IL2057 that #8649 removes.

Verification

  • dotnet build -warnaserror on Akka.Hosting and all five Hosting test projects: clean, 0 warnings.
  • Ran all five Hosting test projects once: Akka.Hosting.Tests (140), Akka.Remote.Hosting.Tests (16), Akka.Cluster.Hosting.Tests (34), Akka.Persistence.Hosting.Tests (24), Akka.Hosting.TestKit.Xunit2.Tests (9), Akka.Hosting.TestKit.Tests (306) - all passing.
  • Akka.API.Tests Hosting-related approvals (ApproveHosting, ApproveRemoteHosting, ApproveClusterHosting, ApprovePersistenceHosting, ApproveHostingTestKit): all passing against the updated baseline.
  • Built a throwaway console app (not part of this repo) referencing this branch's Akka/Akka.Hosting/Akka.DependencyInjection via ProjectReference, calling AddAkka, WithHealthCheck<T> and the obsolete LogMessageFormatter setter, and published it Native AOT (dotnet publish -r linux-x64 -c Release -p:PublishAot=true -p:CppCompilerAndLinker=gcc -p:LinkerFlavor=bfd):
    • Before this fix: publish succeeds with warnings (IL2091 x2, IL2070 x1 from the three sites above); running the binary throws System.InvalidOperationException: A suitable constructor for type 'Akka.Hosting.AkkaHostedService' could not be located. out of host.StartAsync() - the exact reported crash.
    • After this fix: those three warnings are gone (the only remaining Hosting-sourced warning is the pre-existing, out-of-scope akka.extensions one). The app gets past AddHostedService/DI activation and into ActorSystem creation, where it now fails on a separate, already-known, unrelated issue: Akka.Streams.Serialization.StreamRefSerializer is not yet in the built-in serializer table used when Akka.DynamicTypeLoading is off - a gap in Akka.Streams' AOT support, not something this PR touches.
    • Total IL2xxx warnings in that publish: 8 before, 5 after (Hosting-sourced: 4 before, 1 after - the one left is the tracked akka.extensions gap).

Test plan

  • dotnet build -warnaserror on Akka.Hosting and all Hosting test projects
  • Ran all Hosting test projects once
  • Akka.API.Tests Hosting approvals pass against updated baseline
  • Native AOT publish of a throwaway app proves the crash before this fix and its absence after

AddAkka<T> forwards T into AddHostedService<T>, WithHealthCheck<T>
forwards T into ActivatorUtilities.GetServiceOrCreateInstance<T>, and
LoggerConfigBuilder.LogMessageFormatter reflects on its Type value with
GetConstructor - none of the three carried the
DynamicallyAccessedMembers(PublicConstructors) annotation those APIs
require, so a Native AOT publish trimmed away the constructor
reflection metadata and AddAkka failed at startup with "no suitable
constructor". Propagate the same annotation through
WithDefaultLogMessageFormatter<T>, which assigns into
LogMessageFormatter.

Grepped Akka.Hosting, Akka.Remote.Hosting, Akka.Cluster.Hosting and
Akka.Persistence.Hosting for the same pattern (AddHostedService,
AddSingleton<TService,TImpl>, ActivatorUtilities, Activator.CreateInstance<T>).
The other generic type parameters found (ActorRegistry's TKey/TActor,
Cluster.Hosting's per-entity TKey, Persistence.Hosting's TAdapter) are
only ever used as typeof(T) dictionary keys or config values, not
passed into a DynamicallyAccessedMembers-requiring API, so they need
no change. akka.extensions / WithExtension<T> is out of scope here -
PR akkadotnet#8649 covers it.

Updated the Hosting API approval baseline for the new attributes.
@Aaronontheweb Aaronontheweb added the AOT Ahead-of-Time (AOT) Compilation label Sep 28, 2026
…r row, shorter comments

The formatter getter returned an unannotated field (IL2078 under the trim
analyzer). The annotations are source- and binary-compatible, so they don't
need a BREAKING_CHANGES 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

@Aaronontheweb
Aaronontheweb merged commit 33710a3 into akkadotnet:dev Sep 28, 2026
16 checks passed
@Aaronontheweb
Aaronontheweb deleted the fix/hosting-aot-annotations branch September 28, 2026 18:46
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant