Skip to content

Upgrade NATS transport to NATS.NET 3.3.0 push consumers - #1818

Open
yang-xiaodong wants to merge 1 commit into
masterfrom
codex/upgrade-nats-net-3.3.0
Open

yang-xiaodong wants to merge 1 commit into
masterfrom
codex/upgrade-nats-net-3.3.0

Conversation

@yang-xiaodong

Copy link
Copy Markdown
Member

Description:

The NATS transport currently depends on NATS.Client 1.1.8. Migrate it to NATS.NET 3.3.0, whose public push-consumer API allows CAP to retain durable queue subscriptions: instances in the same group compete for messages, while different groups receive their own copy.

Existing consumers retain their durable names, delivery subjects and acknowledgment progress, allowing old and new clients to coexist during rolling upgrades and rollbacks.

Issue(s) addressed:

Changes:

  • Replace NATS.Client with NATS.Client.JetStream 3.3.0 and its Core dependency.
  • Migrate connection pooling, publishing, consumption and acknowledgments to asynchronous APIs; explicitly preserve raw message bytes and CAP headers.
  • Treat duplicate publish acknowledgments as success so CAP does not keep retrying messages already stored by JetStream.
  • Look up and validate existing push consumers before creating new ones, and handle concurrent consumer creation without deleting existing resources.
  • Track consumer tasks, bound group concurrency, drain in-flight callbacks during shutdown, and report connection failures to CAP for recovery.
  • Preserve existing stream settings and merge subjects during stream updates.
  • Add NATS integration tests and update English and Chinese configuration and migration documentation.

Affected components:

  • DotNetCore.CAP.NATS.
  • New DotNetCore.CAP.NATS.Test project and solution registration.
  • English and Chinese NATS transport documentation.

How to test:

  1. Start NATS Server with JetStream enabled, listening on localhost:4222. Set CAP_NATS_TEST_URL to use a different endpoint.
  2. Run dotnet test test/DotNetCore.CAP.NATS.Test/DotNetCore.CAP.NATS.Test.csproj.
  3. To include server-restart recovery, set CAP_NATS_DOCKER_TEST=1 and rerun. This test creates, restarts and removes a separate container; it does not restart the configured server. CAP_NATS_DOCKER_IMAGE can select the server image.
  4. Run dotnet test test/DotNetCore.CAP.Test/DotNetCore.CAP.Test.csproj.
  5. Run dotnet pack src/DotNetCore.CAP.NATS/DotNetCore.CAP.NATS.csproj --configuration Release.

Local validation with NATS Server 2.10.22:

  • 15 NATS integration tests passed, including old/new client coexistence, old pending-message takeover, rollback, group delivery, deduplication, ACK/NAK, concurrency, shutdown and isolated server restart.
  • 73 CAP core tests passed.
  • Release build and NuGet packaging succeeded.
  • Staged diff whitespace checks passed.

Additional notes:

This changes public native configuration types and the custom connection-pool interface. Options now uses NatsOpts; StreamOptions uses Action; ConsumerOptions returns NatsJSPushConsumerOpts; CustomHeadersBuilder receives INatsJSMsg<byte[]> directly. Custom pools use asynchronous rent/return methods and INatsConnection. Simple UseNATS(string) configuration remains unchanged.

ConsumerOptions configures new consumers; existing server-side configuration is validated and reused. CAP continues to acknowledge after receive storage/enqueue, with business-method retries managed by CAP. Migration details and the NATS.NET 3.3.0 limitation around SubOpts on reused consumers are documented.

The existing Microsoft.Build.Tasks.Git 10.0.203 dependency produces an NU1902 warning during validation; it is outside this change.

Checklist:

  • I have tested my changes locally
  • I have added necessary documentation
  • I have updated the relevant tests
  • My changes follow the project's code style guidelines

Copilot AI balanced review requested due to automatic review settings October 7, 2026 14:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Concurrent consumer creation can still fail when NATS returns conflict code 10105.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Migrates the NATS transport to NATS.NET 3.3.0 push consumers while preserving durable subscriptions and rolling-upgrade compatibility.

Changes:

  • Migrates publishing, consumption, pooling, and acknowledgments to asynchronous NATS.NET APIs.
  • Preserves durable consumers and stream configuration.
  • Adds integration tests and migration documentation.
File Description
CAP.sln Registers the NATS test project.
src/​DotNetCore.CAP.NATS/​CAP.NATSOptions.cs Updates native configuration APIs.
src/​DotNetCore.CAP.NATS/​DotNetCore.CAP.NATS.csproj Upgrades the NATS dependency.
src/​DotNetCore.CAP.NATS/​IConnectionPool.cs Defines asynchronous pool operations.
src/​DotNetCore.CAP.NATS/​IConnectionPool.Default.cs Implements asynchronous pooling.
src/​DotNetCore.CAP.NATS/​ITransport.NATS.cs Migrates publishing to NATS.NET.
src/​DotNetCore.CAP.NATS/​NATSConsumerClient.cs Implements durable push consumption.
src/​DotNetCore.CAP.NATS/​NATSConsumerClientFactory.cs Connects and disposes consumers asynchronously.
test/​DotNetCore.CAP.NATS.Test/​DotNetCore.CAP.NATS.Test.csproj Configures the integration-test project.
test/​DotNetCore.CAP.NATS.Test/​DockerRestartTests.cs Tests restart recovery.
test/​DotNetCore.CAP.NATS.Test/​NatsIntegrationTests.cs Covers transport and compatibility behavior.
test/​DotNetCore.CAP.NATS.Test/​NatsTestScope.cs Provides NATS test infrastructure.
test/​DotNetCore.CAP.NATS.Test/​README.md Documents integration-test execution.
docs/​content/​user-guide/​en/​transport/​nats.md Updates English migration guidance.
docs/​content/​user-guide/​zh/​transport/​nats.md Updates Chinese migration guidance.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +199 to +201
catch (NatsJSApiException conflict) when (conflict.Error.ErrCode is 10013 or 10148)
{
OnLogCallback!(new LogMessageEventArgs()
{
LogType = MqLogType.ConnectError,
Reason = $"An error was encountered when attempting to subscribe to subject: {subject}.{Environment.NewLine}" +
$"{e.Message}"
});
consumer = await js.GetPushConsumerAsync(stream, opts.DurableName, _stopping.Token).ConfigureAwait(false);

This branch has not been deployed

No deployments
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.

2 participants