Repository navigation
Hosting: register WithExtension<T> through ExtensionsSetup - #8649
Merged
Merged
Conversation
Aaronontheweb
force-pushed
the
feature/aot-ext-2-hosting-extensions-setup
branch
from
September 25, 2026 13:44
253c9f1 to
b4d38bf
Compare
4 tasks done
Aaronontheweb
added a commit
that referenced
this pull request
Sep 28, 2026
* Add missing trimming annotations to Akka.Hosting for Native AOT 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 #8649 covers it. Updated the Hosting API approval baseline for the new attributes. * Hosting AOT annotations: annotate the formatter field, drop the ledger 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
added this pull request to stack #8662
September 29, 2026 13:53
Aaronontheweb
force-pushed
the
feature/aot-ext-2-hosting-extensions-setup
branch
from
September 29, 2026 18:24
b4d38bf to
525194e
Compare
WithExtension<T>() now captures a factory for T (annotated with [DynamicallyAccessedMembers(PublicParameterlessConstructor)]) and the ActorSystem factory passes the ids in an ExtensionsSetup, instead of writing assembly-qualified names into akka.extensions. Hosting no longer reads akka.extensions either, so its Type.GetType call is gone; any user-supplied akka.extensions reaches core unchanged. An ExtensionsSetup the user added through AddSetup is kept. WithExtensions(params Type[]) still creates ids by reflection and is marked [RequiresUnreferencedCode].
…ilure and HOCON pass-through A throwing extension-id constructor now fails startup with a ConfigurationException that names the type, instead of a bare TargetInvocationException from DI. New specs cover that, and an unresolvable akka.extensions entry next to WithExtension reaching core and being logged there.
Aaronontheweb
force-pushed
the
feature/aot-ext-2-hosting-extensions-setup
branch
from
September 30, 2026 02:00
525194e to
3a118d8
Compare
Aaronontheweb
deleted the
feature/aot-ext-2-hosting-extensions-setup
branch
September 30, 2026 02:39
Aaronontheweb
added a commit
to Aaronontheweb/akka.net
that referenced
this pull request
Sep 30, 2026
Review findings on the Hosting canary: - The extension check always passed: WithExtension<T,TI>() resolves-or-creates, so marking it proved nothing. Require HasExtension<CanaryExtension>() before that call, which only reads. - The health check accepted a report with zero entries. Require the 'akka.actorsystem' key WithActorSystemLivenessCheck() actually registers. - Comments describing WithExtension<T>() as an akka.extensions/Type.GetType round-trip were stale since akkadotnet#8649, which moved it to ExtensionsSetup. Corrected in CanaryExtension.cs, Program.cs, and the README. - WatchdogLoggerProvider now also accepts Information and waits for a dedicated marker line before the final ThrowIfAnyProblems, closing a race and independently proving Akka's logs reach Microsoft.Extensions.Logging - if the marker never arrives, the run fails. - Dropped the CI self-test step and its fixture for this job: it only re-exercises the checker's "measured nothing" branch, which the core canary already covers. - Dropped the unused RootAkka ItemGroup - this canary stays unrooted-only - and the now-redundant Akka/Akka.DependencyInjection ProjectReferences (both come in transitively through Akka.Hosting). - Added a 300s timeout to the CI run step. Cuts: removed NotifyActor/NotificationSink and AssertTellAsync (every Ask reply is already a Tell), AddHocon/AssertHocon, and the redundant TrimmerSingleWarn CLI flag (set once in the csproj). Shortened the README, YAML comments, csproj comments, and PrintFailure. Made AssertExtensionAsync synchronous now that it has no await.
Aaronontheweb
added a commit
that referenced
this pull request
Sep 30, 2026
* AOT: Akka.Hosting canary app and CI job Promotes the Akka.Hosting Native AOT prototype (spike/aot-hosting-canary) to a real canary alongside the plain-core one: - src/aot/Akka.Hosting.AOT.App: boots through Host.CreateApplicationBuilder + AddAkka(...), exercising AddHocon, a custom WithExtension<T>, WithActorSystemLivenessCheck, ConfigureLoggers' AddLoggerFactory, registry/DI-constructed actors, Tell, and DeathWatch. Self-terminates after its assertions pass instead of waiting on an external SIGINT/SIGTERM, so CI gets a deterministic exit. Added to Akka.slnx next to Akka.AOT.App. - scripts/CheckAotWarnings.cs now takes --scope (comma-separated prefixes, default src/core/Akka/), so the same checker gates the Hosting canary's own baseline (src/aot/Akka.Hosting.AOT.App/aot-warnings.baseline.txt) against src/contrib/hosting/, src/contrib/dependencyinjection/, and src/core/Akka.Streams/ - the last because Hosting registers the stream-ref serializer at startup and nothing else watches that surface. src/core/Akka/ itself is left out; the plain-core canary's baseline already covers it. Three known Streams warnings (stream-ref MakeGenericType, SerializationTools.TypeFromString) are baselined with a pointer to #8667. - build-system/pr-validation.yaml: new HostingAotCanary job, Linux, blocking. One unrooted publish serves both the run and the warning check - the three baselined Streams warnings already surface on that real boot, so a second rooted publish would not currently add coverage. Verified locally: unrooted publish is clean from Hosting/DI and matches the expected 4 core + 3 Streams warnings; the app exits 0 and prints '[canary-hosting] OK'; the warning check passes against the new baseline; a temporary Type.GetType probe added to src/contrib/hosting/Akka.Hosting/AkkaHostingExtensions.cs (reverted) proved the check fails on a new warning in scope. * Hosting AOT canary: assertions that can fail, fewer lines Review findings on the Hosting canary: - The extension check always passed: WithExtension<T,TI>() resolves-or-creates, so marking it proved nothing. Require HasExtension<CanaryExtension>() before that call, which only reads. - The health check accepted a report with zero entries. Require the 'akka.actorsystem' key WithActorSystemLivenessCheck() actually registers. - Comments describing WithExtension<T>() as an akka.extensions/Type.GetType round-trip were stale since #8649, which moved it to ExtensionsSetup. Corrected in CanaryExtension.cs, Program.cs, and the README. - WatchdogLoggerProvider now also accepts Information and waits for a dedicated marker line before the final ThrowIfAnyProblems, closing a race and independently proving Akka's logs reach Microsoft.Extensions.Logging - if the marker never arrives, the run fails. - Dropped the CI self-test step and its fixture for this job: it only re-exercises the checker's "measured nothing" branch, which the core canary already covers. - Dropped the unused RootAkka ItemGroup - this canary stays unrooted-only - and the now-redundant Akka/Akka.DependencyInjection ProjectReferences (both come in transitively through Akka.Hosting). - Added a 300s timeout to the CI run step. Cuts: removed NotifyActor/NotificationSink and AssertTellAsync (every Ask reply is already a Tell), AddHocon/AssertHocon, and the redundant TrimmerSingleWarn CLI flag (set once in the csproj). Shortened the README, YAML comments, csproj comments, and PrintFailure. Made AssertExtensionAsync synchronous now that it has no await. * AOT canaries: run the Hosting canary as steps in the existing AotCanary job * Hosting AOT canary: empty baseline now that #8671 removed the stream-ref warnings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
Second PR of the stack; builds on #8648 (
ExtensionsSetup). Review that one first. This PR's own diff is one commit.WithExtension<T>()now has[DynamicallyAccessedMembers(PublicParameterlessConstructor)]onT(same as core'sActorSystemWithExtensions.WithExtension<T, TI>). It captures a factory, and the ActorSystem factory passes the ids in anExtensionsSetupinstead of writingT's assembly-qualified name intoakka.extensions.akka.extensions. The oldAddExtensions()calledType.GetTypeon every listed name, which is its own trim warning. It's gone. User-suppliedakka.extensionsreaches core unchanged, where the first-party table or reflection handles it.WithExtensions(params Type[])still uses reflection (Activator.CreateInstance(Type)) and now has[RequiresUnreferencedCode], which points callers toWithExtension<T>().ExtensionsSetupviaAddSetup, Hosting merges it with its own instead of replacing it.WithDistributedDatain Akka.Cluster.Hosting already callsWithExtension<DistributedDataProvider>(); no change needed. The Cluster.Hosting tests pass.Observable changes (added to
BREAKING_CHANGES_V1.6.md)Settings.Config.GetStringList("akka.extensions")no longer lists extensions that Hosting registered. UseSettings.Setup.Get<ExtensionsSetup>()orHasExtension<T>()instead.akka.extensionsentry that doesn't resolve used to be dropped silently by Hosting whenWithExtensionwas also used. Now it reaches core, which logs its usual error.ConfigurationExceptionthat names the type (inner exception attached). Before, core logged and skipped it.Tests
Akka.Hosting.Tests/ExtensionsSpecs, new:WithExtension<T>registers throughExtensionsSetup: the extension is there after startup, and the setup holds exactly that id.akka.extensions: a user HOCON list passes through exactly as given, and theWithExtensionextension still starts.ExtensionsSetupis kept alongside Hosting's.ConfigurationExceptionnaming the type.akka.extensionsentry next toWithExtensionreaches core, which logs an error (captured by a small recording logger, since the error fires during startup before anEventFiltercould be attached).Checklist
dotnet build -c Release -warnaserror: Akka.Hosting, Cluster/Remote/Persistence.Hosting and all six Hosting test projectsExtensionsSpecs5x greenAkka.API.Tests:ApproveHostingchanged only by the two new attributes[canary] OKwith the same 4 warnings; rootedCheckAotWarningsreports no new warnings (the canary doesn't reference Hosting, so this is a no-regression check)