Skip to content

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.MessagingModel is 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.MessagingModel exposes IEventBus with SendCommand<TCommand> and PublishEvent<TEvent>, plus ICommand, 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), and MessagingModel.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

  1. Application and domain code in the Factory depends only on ConnectSoft.Extensions.MessagingModel contracts. Event and command types must not reference MassTransit, NServiceBus, Orleans or broker-specific types.
  2. 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.
  3. 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.
  4. 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.
  5. 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.cs
  • ConnectSoft.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.cs and transport options
  • ConnectSoft.Extensions.AI.Factory.Messaging.MassTransit (publisher only)
  • Verification record V-A19, V-A20 in handoffs/2026-10-09-independent-review/verification-record.md
  • 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.