Skip to content

AOT: a broker module's AOT serialization branch must fail at composition time, not at first delivery #516

Description

@Greven145

Goal

Ensure that when a broker module gains a runtime-branched AOT serialization registration, a missing AOT serialization opt-in fails at composition or startup time rather than at first message delivery.

Current state on master (verified at 7408c31)

The defect described in the original body is not present in this repository, because the design that would introduce it has not been adopted here.

  • src/Chatter.MessageBrokers.RabbitMQ/src/Chatter.MessageBrokers.RabbitMQ/DependencyInjection/Extensions.cs:110 registers the Body Converter unconditionally: builder.Services.AddSingleton<IBrokeredMessageBodyConverter, RabbitMqBodyConverter>();. It is a singleton with a type-based service descriptor — no factory delegate, no branch.
  • RabbitMqBodyConverter (RabbitMqBodyConverter.cs) has no constructor at all; it calls the published Wire Serialization capability ChatterJson.Deserialize<TBody> (line 10) and ChatterJson.Serialize(body) (line 20).
  • Nothing in the repository registers or resolves a JsonSerializerOptions from DI, and RuntimeFeature.IsDynamicCodeSupported appears nowhere.
  • WithAotJsonSerialization does not exist. Phase 3 (AOT Phase 3: ChatterJson serialization dual-path #279) is still open.

The code quoted in the original body comes from a fork PR that is not in this repository's history.

Why this stays open

The hazard it identifies is real and is not currently owned by any other issue. The moment a broker module registers its Body Converter through a factory delegate that resolves an AOT-specific dependency — the shape proposed by #431 and #509 — that dependency is resolved lazily, on the first scope that asks for IBrokeredMessageBodyConverter. In practice that is the first real send or receive, not the AddRabbitMq(...) call. An application that forgets the AOT opt-in would boot cleanly and fail only under production traffic.

Note also the constraint already recorded on src/Chatter.MessageBrokers/CONTEXT.md: a registration factory must not resolve a Brokered Message Receiver's dependency graph from a using var scope, because the scope and every scoped member die as the factory returns while the singleton hosted service keeps the dead graph. Any eager-validation mechanism must respect that, and ADR-0022 ("registration factories open no scope — the component that bounds the graph owns it") is the governing decision.

Reframed scope

This is an acceptance criterion on whichever change first introduces a runtime-branched serialization registration, rather than a standalone defect fix. It should be satisfied by, or explicitly deferred from, #279, #431 and #509.

  • Decide where eager validation belongs: an IHostedService or IStartupFilter-style check that runs at host start, or a validation pass at registration time. Calling services.BuildServiceProvider() mid-registration is not acceptable — it builds a second container and is the anti-pattern this issue must avoid, not adopt.
  • Confirm the mechanism honors ADR-0022 and the CONTEXT.md _Avoid_ above: no registration factory may open and close a scope around a graph the caller keeps.
  • Apply the same treatment to every broker module that gains the branch, not only Chatter.MessageBrokers.RabbitMQ. Chatter.MessageBrokers.SqlServiceBroker (AOT: route JsonUnicodeBodyConverter (SqlServiceBroker) through GetTypeInfo #515) has the identical Body Converter shape.
  • Add a test that boots a host with the broker registered but without the AOT serialization opt-in, and asserts the failure surfaces at startup rather than at first receive. Under a published Native AOT binary this depends on the harness from AOT Phase 0: Infrastructure and red baseline #276.

If the maintainer prefers fewer open items, this is a reasonable candidate to fold into #279 as an explicit acceptance criterion and close.

Part of #275.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions