Skip to content

v7: UseNats with options from configuration, and headers over NATS - #118

Merged
christopherread merged 1 commit into
v7from
v7-nats
Oct 25, 2026
Merged

christopherread merged 1 commit into
v7from
v7-nats

Conversation

@christopherread

Copy link
Copy Markdown
Owner

Next v7 increment: UseNats() for #84, following the UseRabbitMq() pattern from #112. It also carries message headers, including trace context (#90, as in #116), over NATS. Targets v7.

API

builder.Services.AddObvs(obvs => obvs
    .AddService<IOrderMessage>("orders", service => service
        .UseNats(builder.Configuration.GetSection("Obvs:Orders:Nats"))   // or .UseNats(o => o.Url = "nats://localhost:4222")
        .SerializedWith(new JsonMessageSerializer(), new JsonMessageDeserializerFactory(typeof(JsonMessageDeserializer<>)))));
  • Options: NatsOptions has Url (required). Each service's settings are named options keyed by the service name: IOptionsMonitor<NatsOptions>.Get("orders").
  • Startup checks: a missing URL or serializer fails at startup, inside the same ObvsConfigurationException as any other problem. The message names the configuration key to set (for example Obvs:Orders:Nats:Url) or the method to call.
  • Connections aren't shared. v6's shared NATS connections are process-wide, keyed by URL. With them, stopping one host would close the connection another host in the same process is still using. So each service on each bus gets its own connection.

Headers over NATS

  • Sending: the publisher sends ObvsMessageHeaders as NATS headers. A message without headers is sent as before.
  • Receiving: the source copies NATS headers back onto the received message before subscribers see it. As a result, the receiver's process span continues the sender's trace, and headers the app sets arrive intact.
  • Compatibility: v6 receivers ignore NATS headers, so v6 and v7 services can still exchange messages.

Tests (written first)

  • Configuration (no server): 5 tests in Obvs.NATS.Tests/Hosting/TestUseNats.cs. They cover options from configuration and from code, a missing URL (in configuration and in code), and a missing serializer.
  • End to end (Explicit, real server): 6 tests in TestNatsHosting.cs. They cover:
    • commands and events;
    • request and response through HandleRequest and RequestAsync;
    • two hosts in one process;
    • disposing the bus from a message callback;
    • trace continuation;
    • headers the app sets.
  • Red first: the configuration tests failed before UseNats existed. Once UseNats worked, the two header tests still failed for their real reasons, a missing x-tenant header and a different trace ID, until headers were carried.
  • Mutation check: switching back to shared connections makes the two-hosts test fail.
  • Results:
    • All 8 NATS broker tests (the 6 new ones plus the 2 existing v6 ones) passed 3 runs in a row against a local nats-server.
    • A clean build of the solution has 0 warnings, and all 210 unit tests pass.

Not in this increment

  • Use<Transport>() and header support for Kafka, ActiveMQ and NetMQ.

🤖 Generated with Claude Code

Adds UseNats(IConfiguration) and UseNats(Action<NatsOptions>) for AddObvs,
with startup checks for a missing server address or serializer. Each service
on each bus gets its own connection, since v6's shared connections are
process-wide. Message headers, including trace context, now travel as NATS
headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant