ADR-0012: Messaging port with transport profiles¶
Decision
This page records a decision and its status. A Proposed decision is not binding; an Accepted decision is binding on the Factory until amended or superseded.
- Status: Accepted 2026-10-09 by the product owner (amends ADR-0003, which stays in force except where this ADR changes it)
- Date: 2026-10-09
- Deciders: Dmitry Khaymov (product owner), 2026-10-09; proposed by the 2026-10 independent review
- Tags: messaging, events, transport, ports-and-adapters
Context¶
ADR-0003 selects MassTransit on Azure Service Bus as the primary messaging stack and mirrors envelope fields into broker properties. Since it was recorded:
- The user directed that
ConnectSoft.Extensions.MessagingModelis the preferred messaging abstraction, Orleans may be investigated, and no broker is mandatory (2026-10 direction, recorded in the independent review decision log). - The port already exists and is stable:
ConnectSoft.Extensions.MessagingModelexposesIEventBuswithSendCommand<TCommand>andPublishEvent<TEvent>, plusICommand,IEvent,ICommandHandler,IEventHandler(six source files). Consumers pin 1.0.16. - Three adapters exist as separate packages:
MessagingModel.MassTransit(transports RabbitMQ, Azure Service Bus, SQL Server, PostgreSQL; options only, no outbox),MessagingModel.NServiceBus(uses NServiceBus's own outbox), andMessagingModel.Orleans(outbox dispatcher and inbox grains, NHibernate outbox writer, SQL schema, 33 test files). There is no standalone Azure Service Bus adapter; it is a MassTransit transport option. - The reference consumer of the template estate, DerechHaLev / Bereshit 2.0 (seven service projects reference the Orleans adapter in source; deployment status not verified here), approved the Orleans adapter on 2026-07-20 (design decisions MSG1–MSG5) and replaced MassTransit for inter-service messaging in that estate.
- Factory lifecycle events are today published only through
ConnectSoft.Extensions.AI.Factory.Messaging.MassTransit, with no transactional run state behind them. - The documentation references MassTransit on 120 pages and Azure Service Bus on 101 pages, mostly as mandatory statements.
Decision¶
- Application and domain code in the Factory depends only on
ConnectSoft.Extensions.MessagingModelcontracts. Event and command types must not reference MassTransit, NServiceBus, Orleans or broker-specific types. - The transport is a deployment profile selected per host from the existing adapters. A profile must declare, with evidence from its own tests: transaction/outbox behaviour, acknowledgement meaning, deduplication scope and retention, ordering scope, retry ownership, poison handling, replay policy, cancellation, payload limits, schema compatibility, tenant isolation and observability.
- MassTransit on Azure Service Bus becomes one reference profile, documented as such wherever ADR-0003 is cited. The Orleans adapter is a second candidate profile with existing outbox/inbox code and an approved consumer design; NServiceBus is a third.
- Run-state transitions and the events announcing them must be persisted in the same transaction as the outbox record of the selected profile. Publication alone is not evidence of a durable transition.
- The broker property mirroring in ADR-0003 (
cs-event-type,cs-tenant-id,cs-trace-id,cs-correlation-id,cs-schema-version) is retained as the MassTransit profile's mapping, not as a port requirement; ADR-0014 defines the port-level envelope.
Consequences¶
Positive¶
- Reuses the existing port and three adapters; no new bus abstraction.
- Aligns the Factory with the direction already taken by the reference consumer in source without mandating Orleans everywhere.
- Explicit promotion (review note 2026-10-15): the user's direction said Orleans "may be investigated"; decision 3 above lists it as the second candidate profile with an approved consumer design, later pages treat the Orleans outbox/inbox profile as the default for run-state persistence, and ADR-0024 §1 makes Orleans grains the durability substrate. That is a promotion beyond the original wording, taken as the product owner's decision (D46), not derived from measurements.
- Makes delivery guarantees explicit per profile instead of implied by a framework name.
Negative / trade-offs¶
- Roughly 120 pages must be revised from "MassTransit/Azure Service Bus is the stack" to "the port is the contract; this page shows a profile".
- Profile evidence (contract tests per adapter) does not exist yet for the Factory and must be produced before any profile is called qualified.
- Replacing a transport remains a migration project (topology, ordering, persistence), not a DI registration change.
Neutral¶
- Existing MassTransit sagas in templates remain scaffolds until a Factory workflow needs them.
Alternatives considered¶
| Alternative | Why not chosen |
|---|---|
| Keep ADR-0003 unchanged | Contradicts the user's explicit direction and the reference consumer's choice in source; leaves run-state atomicity undefined. |
| Mandate Orleans ecosystem-wide | DerechHaLev's approval is scoped to that estate; Orleans streaming guarantees depend on provider and configuration and are not automatically a durable broker. |
| Invent a Factory-specific bus interface | Duplicates IEventBus; adapters would need reimplementation. |
Evidence¶
ConnectSoft.Extensions.MessagingModel/ConnectSoft.Extensions.MessagingModel/IEventBus.csConnectSoft.Extensions.MessagingModel.Orleans/src/.../OrleansMessagingEventBus.cs,NHibernateOutboxWriter.cs,Grains/OutboxDispatcherGrain.cs,Grains/InboxGrain.cs;docs/design/index.md(approved 2026-07-20)ConnectSoft.Extensions.MessagingModel.MassTransit/src/.../MassTransitAdapter.csand transport optionsConnectSoft.Extensions.AI.Factory.Messaging.MassTransit(publisher only)- Verification record V-A19, V-A20 in
handoffs/2026-10-09-independent-review/verification-record.md
Related¶
- ADR-0003 — amended by this ADR
- ADR-0010 and ADR-0014
- Event-Driven Architecture
- Canonical home: the shared AI/messaging decision is to be recorded in ConnectSoft.Documentation with a Factory supplement (user decision D10); this ADR is the Factory projection.