From d19bbd6579a04cdf734ecd319fa388ee5e97da3f Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Tue, 21 Jan 2025 19:42:40 -0800 Subject: [PATCH 1/9] Start Rabbitmq documentation and upgrade guide --- transports/rabbitmq/connection-settings.md | 2 ++ ...management-api-url_rabbit_[,10).partial.md | 0 ...management-api-url_rabbit_[10,).partial.md | 20 +++++++++++++++++++ transports/upgrades/rabbitmq-9to10.md | 18 +++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 transports/rabbitmq/connection-settings_management-api-url_rabbit_[,10).partial.md create mode 100644 transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md diff --git a/transports/rabbitmq/connection-settings.md b/transports/rabbitmq/connection-settings.md index 11bb185f434..d716f3d1697 100644 --- a/transports/rabbitmq/connection-settings.md +++ b/transports/rabbitmq/connection-settings.md @@ -101,6 +101,8 @@ snippet: rabbitmq-external-auth-mechanism partial: add-cluster-node +partial: management-api-url + ## Controlling the prefetch count When consuming messages from the broker, throughput can be improved by having the consumer [prefetch](https://www.rabbitmq.com/consumer-prefetch.html) additional messages. diff --git a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[,10).partial.md b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[,10).partial.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md new file mode 100644 index 00000000000..361ee43c939 --- /dev/null +++ b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md @@ -0,0 +1,20 @@ +## Configuring RabbitMQ delivery limit check + +> [!NOTE] +> RabbitMQ version 4.0 and above sets a default delivery limit value of 20 messages on queue creation. Setting the delivery limit to unlimited (-1) is critical for the proper functioning of the NServiceBus recoverability process. Ensure that this setting is configured in your RabbitMQ node if the check is disabled. + +The transport can verify that the RabbitMQ delivery limit is set to unlimited (-1) using the management API. This ensures that the NServiceBus recoverability process works correctly, preventing potential message loss. For this check to function, the RabbitMQ management plugin must be enabled on the RabbitMQ node. + +To configure the HTTP client and perform the delivery limit check, set the authentication details as follows: + +```csharp +var transport = new RabbitMQTransport(RoutingTopology.Conventional(QueueType.Quorum), "host=localhost") +{ + ManagementApiUrl = "http://username:password@localhost:15672"; +} + +// Or + +var transport = endpointConfiguration.UseTransport(); +transport.ManagementApiUrl("http://username:password@localhost:15672"); +``` \ No newline at end of file diff --git a/transports/upgrades/rabbitmq-9to10.md b/transports/upgrades/rabbitmq-9to10.md index 52580f522dd..07e6e9ae992 100644 --- a/transports/upgrades/rabbitmq-9to10.md +++ b/transports/upgrades/rabbitmq-9to10.md @@ -16,6 +16,24 @@ The transport now uses [RabbitMQ.Client v7.0.0](https://www.nuget.org/packages/R For details, see the [RabbitMQ client changelog](https://github.com/rabbitmq/rabbitmq-dotnet-client/releases/tag/v7.0.0). +## RabbitMQ Management API + +The transport has introduced a client connection to the HTTP-based RabbitMQ management API. This requires the [rabbitmq management plugin](https://www.rabbitmq.com/docs/management#getting-started) to be enabled on the node. The client uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) to connect with the RabbitMQ management API and is configured via the `ManagementApiUrl` transport property. + +For more details about the configuration, see [Configuring RabbitMQ delivery limit check](/transports/rabbitmq/connection-settings.md#configuring-rabbitmq-delivery-limit-check). + +```CSharp +var transport = new RabbitMQTransport(RoutingTopology.Conventional(QueueType.Quorum), "host=localhost") +{ + ManagementApiUrl = "http://username:password@localhost:15672"; +} + +// Or + +var transport = endpointConfiguration.UseTransport(); +transport.ManagementApiUrl("http://username:password@localhost:15672"); +``` + ### `IRoutingTopology` Updates The following changes have been made to `IRoutingTopology`: From 2072647087c73c6bac5c98fc51baf32cae84b0a3 Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Wed, 22 Jan 2025 22:31:21 -0800 Subject: [PATCH 2/9] Add rabbit version 10 snippet project --- Snippets/Rabbit/Rabbit.sln | 6 + .../AccessToBasicDeliverEventArgs.cs | 18 ++ .../Rabbit/Rabbit_10/MyRoutingTopology.cs | 42 ++++ .../RabbitMQNonPersistentDeliveryMode.cs | 19 ++ Snippets/Rabbit/Rabbit_10/Rabbit_10.csproj | 12 + Snippets/Rabbit/Rabbit_10/Usage.cs | 229 ++++++++++++++++++ Snippets/Rabbit/Rabbit_10/prerelease.txt | 0 .../Rabbit_10/rabbitmq-connection-tls.txt | 3 + 8 files changed, 329 insertions(+) create mode 100644 Snippets/Rabbit/Rabbit_10/AccessToBasicDeliverEventArgs.cs create mode 100644 Snippets/Rabbit/Rabbit_10/MyRoutingTopology.cs create mode 100644 Snippets/Rabbit/Rabbit_10/RabbitMQNonPersistentDeliveryMode.cs create mode 100644 Snippets/Rabbit/Rabbit_10/Rabbit_10.csproj create mode 100644 Snippets/Rabbit/Rabbit_10/Usage.cs create mode 100644 Snippets/Rabbit/Rabbit_10/prerelease.txt create mode 100644 Snippets/Rabbit/Rabbit_10/rabbitmq-connection-tls.txt diff --git a/Snippets/Rabbit/Rabbit.sln b/Snippets/Rabbit/Rabbit.sln index 49fe54ee229..84dba540ff7 100644 --- a/Snippets/Rabbit/Rabbit.sln +++ b/Snippets/Rabbit/Rabbit.sln @@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rabbit_9.1", "Rabbit_9.1\Ra EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rabbit_9.2", "Rabbit_9.2\Rabbit_9.2.csproj", "{2F242592-4E40-4C87-90A4-32055B11544F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rabbit_10", "Rabbit_10\Rabbit_10.csproj", "{F99C022C-1BAD-4C78-8069-C34C3EB9AE5F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {2F242592-4E40-4C87-90A4-32055B11544F}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F242592-4E40-4C87-90A4-32055B11544F}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F242592-4E40-4C87-90A4-32055B11544F}.Release|Any CPU.Build.0 = Release|Any CPU + {F99C022C-1BAD-4C78-8069-C34C3EB9AE5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F99C022C-1BAD-4C78-8069-C34C3EB9AE5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F99C022C-1BAD-4C78-8069-C34C3EB9AE5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F99C022C-1BAD-4C78-8069-C34C3EB9AE5F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Snippets/Rabbit/Rabbit_10/AccessToBasicDeliverEventArgs.cs b/Snippets/Rabbit/Rabbit_10/AccessToBasicDeliverEventArgs.cs new file mode 100644 index 00000000000..8e5d9ea2857 --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/AccessToBasicDeliverEventArgs.cs @@ -0,0 +1,18 @@ +using System; +using System.Threading.Tasks; +using NServiceBus.Pipeline; +using RabbitMQ.Client.Events; + +#region rabbitmq-access-to-event-args +class AccessToBasicDeliverEventArgs : Behavior +{ + public override Task Invoke(IIncomingContext context, Func next) + { + var userIdOnBroker = context.Extensions.Get().BasicProperties.UserId; + + //do something useful + + return next(); + } +} +#endregion \ No newline at end of file diff --git a/Snippets/Rabbit/Rabbit_10/MyRoutingTopology.cs b/Snippets/Rabbit/Rabbit_10/MyRoutingTopology.cs new file mode 100644 index 00000000000..489a1e530ff --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/MyRoutingTopology.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using NServiceBus.Transport; +using NServiceBus.Transport.RabbitMQ; +using NServiceBus.Unicast.Messages; +using RabbitMQ.Client; + +class MyRoutingTopology : + IRoutingTopology +{ + public MyRoutingTopology(bool createDurableExchangesAndQueues) + { + } + + public void SetupSubscription(IModel channel, MessageMetadata type, string subscriberName) + { + } + + public void TeardownSubscription(IModel channel, MessageMetadata type, string subscriberName) + { + } + + public void Publish(IModel channel, Type type, OutgoingMessage message, IBasicProperties properties) + { + } + + public void Send(IModel channel, string address, OutgoingMessage message, IBasicProperties properties) + { + } + + public void RawSendInCaseOfFailure(IModel channel, string address, ReadOnlyMemory body, IBasicProperties properties) + { + } + + public void Initialize(IModel channel, IEnumerable receivingAddresses, IEnumerable sendingAddresses) + { + } + + public void BindToDelayInfrastructure(IModel channel, string address, string deliveryExchange, string routingKey) + { + } +} \ No newline at end of file diff --git a/Snippets/Rabbit/Rabbit_10/RabbitMQNonPersistentDeliveryMode.cs b/Snippets/Rabbit/Rabbit_10/RabbitMQNonPersistentDeliveryMode.cs new file mode 100644 index 00000000000..0969b1c5b82 --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/RabbitMQNonPersistentDeliveryMode.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using NServiceBus; + +class RabbitMQNonPersistentDeliveryMode +{ + public async Task RequestNonPersistent(IMessageHandlerContext context) + { + #region rabbitmq-non-persistent-delivery-mode + var options = new SendOptions(); + + options.RouteToThisEndpoint(); + options.UseNonPersistentDeliveryMode(); + + await context.Send(new MyMessage(), options); + #endregion + } + + class MyMessage { } +} diff --git a/Snippets/Rabbit/Rabbit_10/Rabbit_10.csproj b/Snippets/Rabbit/Rabbit_10/Rabbit_10.csproj new file mode 100644 index 00000000000..1841a262161 --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/Rabbit_10.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + + + + + + + + diff --git a/Snippets/Rabbit/Rabbit_10/Usage.cs b/Snippets/Rabbit/Rabbit_10/Usage.cs new file mode 100644 index 00000000000..9ea19cbdb74 --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/Usage.cs @@ -0,0 +1,229 @@ +using System; +using System.Security.Cryptography.X509Certificates; + +using NServiceBus; + +class Usage +{ + Usage(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-basic + + endpointConfiguration.UseTransport(); + + #endregion + } + + void CustomConnectionString(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-connectionstring-in-code + + var transport = endpointConfiguration.UseTransport(); + transport.ConnectionString("My custom connection string"); + + #endregion + } + + void CustomIdStrategy(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-custom-id-strategy + + var transport = endpointConfiguration.UseTransport(); + transport.CustomMessageIdStrategy( + customIdStrategy: deliveryArgs => + { + var headers = deliveryArgs.BasicProperties.Headers; + return headers["MyCustomId"].ToString(); + }); + + #endregion + } + + void UseConventionalRoutingTopology(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-useconventionalroutingtopology + + var transport = endpointConfiguration.UseTransport(); + transport.UseConventionalRoutingTopology(QueueType.Quorum); + + #endregion + } + + void UseDirectRoutingTopology(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-usedirectroutingtopology + + var transport = endpointConfiguration.UseTransport(); + transport.UseDirectRoutingTopology(QueueType.Quorum); + + #endregion + } + + void UseDirectRoutingTopologyWithCustomConventions(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-usedirectroutingtopologywithcustomconventions + + var transport = endpointConfiguration.UseTransport(); + transport.UseDirectRoutingTopology( + QueueType.Quorum, + routingKeyConvention: MyRoutingKeyConvention, + exchangeNameConvention: () => "MyTopic"); + + #endregion + } + + string MyRoutingKeyConvention(Type type) + { + throw new NotImplementedException(); + } + + void UseRoutingTopology5_0(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-useroutingtopologyDelegate + + var transport = endpointConfiguration.UseTransport(); + transport.UseCustomRoutingTopology( + topologyFactory: createDurableExchangesAndQueues => + { + return new MyRoutingTopology(createDurableExchangesAndQueues); + }); + + #endregion + } + + void UseCustomCircuitBreakerSettings(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-custom-breaker-settings-time-to-wait-before-triggering-code + + var transport = endpointConfiguration.UseTransport(); + transport.TimeToWaitBeforeTriggeringCircuitBreaker(TimeSpan.FromMinutes(2)); + + #endregion + } + + void PrefetchMultiplier(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-prefetch-multiplier + + var transport = endpointConfiguration.UseTransport(); + transport.PrefetchMultiplier(4); + + #endregion + } + + void PrefetchCount(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-config-prefetch-count + + var transport = endpointConfiguration.UseTransport(); + transport.PrefetchCount(100); + + #endregion + } + + void SetClientCertificateFile(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-client-certificate-file + + var transport = endpointConfiguration.UseTransport(); + transport.SetClientCertificate("path", "password"); + + #endregion + } + + void SetClientCertificate(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-client-certificate + + var transport = endpointConfiguration.UseTransport(); + transport.SetClientCertificate(new X509Certificate2("/path/to/certificate")); + + #endregion + } + + void DisableRemoteCertificateValidation(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-disable-remote-certificate-validation + + var transport = endpointConfiguration.UseTransport(); + transport.DisableRemoteCertificateValidation(); + + #endregion + } + + void UseExternalAuthMechanism(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-external-auth-mechanism + + var transport = endpointConfiguration.UseTransport(); + transport.UseExternalAuthMechanism(); + + #endregion + } + + void ChangeRequestedHeartbeatForDebugging(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-debug-api + + var transport = endpointConfiguration.UseTransport(); + transport.SetHeartbeatInterval(TimeSpan.FromMinutes(10)); + + #endregion + } + + void ChangeHeartbeatInterval(EndpointConfiguration endpointConfiguration) + { + #region change-heartbeat-interval + + var transport = endpointConfiguration.UseTransport(); + transport.SetHeartbeatInterval(TimeSpan.FromSeconds(30)); + + #endregion + } + + void ChangeNetworkRecoveryInterval(EndpointConfiguration endpointConfiguration) + { + #region change-network-recovery-interval + + var transport = endpointConfiguration.UseTransport(); + transport.SetNetworkRecoveryInterval(TimeSpan.FromSeconds(30)); + + #endregion + } + + void DisableDurableExchangesAndQueues(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-disable-durable-exchanges + + var transport = endpointConfiguration.UseTransport(); + transport.DisableDurableExchangesAndQueues(); + + #endregion + } + + void AddClusterNode(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-add-cluster-node + + var transport = endpointConfiguration.UseTransport(); + transport.AddClusterNode("node2", useTls: false); + + #endregion + + #region rabbitmq-add-cluster-node-with-port + + transport.AddClusterNode("node2", 5675, useTls: true); + + #endregion + } + + void SetManagementApiUrl(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-management-api-url + + var transport = endpointConfiguration.UseTransport(); + transport.ManagementApiUrl("http(s)://{username}:{password}@{host}:{port}"); + + #endregion + } +} diff --git a/Snippets/Rabbit/Rabbit_10/prerelease.txt b/Snippets/Rabbit/Rabbit_10/prerelease.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Snippets/Rabbit/Rabbit_10/rabbitmq-connection-tls.txt b/Snippets/Rabbit/Rabbit_10/rabbitmq-connection-tls.txt new file mode 100644 index 00000000000..885b188ba9a --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/rabbitmq-connection-tls.txt @@ -0,0 +1,3 @@ +startcode rabbitmq-connection-tls +host=broker1;UseTls=true +endcode \ No newline at end of file From 797447b0061738d18fdaeaadb024a7873828274c Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Wed, 22 Jan 2025 22:31:53 -0800 Subject: [PATCH 3/9] Update transport documentation --- ...management-api-url_rabbit_[10,).partial.md | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md index 361ee43c939..9bb57dad116 100644 --- a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md +++ b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md @@ -1,20 +1,17 @@ -## Configuring RabbitMQ delivery limit check +## Configuring RabbitMQ delivery limit validation -> [!NOTE] -> RabbitMQ version 4.0 and above sets a default delivery limit value of 20 messages on queue creation. Setting the delivery limit to unlimited (-1) is critical for the proper functioning of the NServiceBus recoverability process. Ensure that this setting is configured in your RabbitMQ node if the check is disabled. +In RabbitMQ version 4.0 and above, queues are created with a default delivery limit of 20. However, for the NServiceBus recoverability process to function properly, the delivery limit should be set to unlimited (-1). + +The RabbitMQ transport can verify that the RabbitMQ delivery limit is set to unlimited (-1) using the management API. This requires the [rabbitmq management plugin](https://www.rabbitmq.com/docs/management#getting-started) to be enabled on the RabbitMQ node. The management API uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) to connect. -The transport can verify that the RabbitMQ delivery limit is set to unlimited (-1) using the management API. This ensures that the NServiceBus recoverability process works correctly, preventing potential message loss. For this check to function, the RabbitMQ management plugin must be enabled on the RabbitMQ node. +To configure the management API and perform the delivery limit validation, set the URL details as follows: -To configure the HTTP client and perform the delivery limit check, set the authentication details as follows: +snippet: rabbitmq-management-api-url -```csharp -var transport = new RabbitMQTransport(RoutingTopology.Conventional(QueueType.Quorum), "host=localhost") -{ - ManagementApiUrl = "http://username:password@localhost:15672"; -} +> [!NOTE] +> If the management API URL is not set, the transport will use the credentials from the broker connection string and the default management API URL of `http://localhost:15672/api` to attempt to connect to the RabbitMQ management API. -// Or +The use of the management API and the validation of the delivery limit can be disabled by calling the `DoNotUseManagementApi()` transport method. -var transport = endpointConfiguration.UseTransport(); -transport.ManagementApiUrl("http://username:password@localhost:15672"); -``` \ No newline at end of file +> [!WARNING] +> Potential message loss can occur if the delivery limit is not set to unlimited on the RabbitMQ node. If the delivery limit is not set to unlimited, the recoverability process may not function as intended. From 263bae26fcf03b0223e6416b801521f9606dce48 Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Wed, 22 Jan 2025 22:32:21 -0800 Subject: [PATCH 4/9] Update upgrade guide --- transports/upgrades/rabbitmq-9to10.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/transports/upgrades/rabbitmq-9to10.md b/transports/upgrades/rabbitmq-9to10.md index 07e6e9ae992..2743eaf0e73 100644 --- a/transports/upgrades/rabbitmq-9to10.md +++ b/transports/upgrades/rabbitmq-9to10.md @@ -20,19 +20,7 @@ For details, see the [RabbitMQ client changelog](https://github.com/rabbitmq/rab The transport has introduced a client connection to the HTTP-based RabbitMQ management API. This requires the [rabbitmq management plugin](https://www.rabbitmq.com/docs/management#getting-started) to be enabled on the node. The client uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) to connect with the RabbitMQ management API and is configured via the `ManagementApiUrl` transport property. -For more details about the configuration, see [Configuring RabbitMQ delivery limit check](/transports/rabbitmq/connection-settings.md#configuring-rabbitmq-delivery-limit-check). - -```CSharp -var transport = new RabbitMQTransport(RoutingTopology.Conventional(QueueType.Quorum), "host=localhost") -{ - ManagementApiUrl = "http://username:password@localhost:15672"; -} - -// Or - -var transport = endpointConfiguration.UseTransport(); -transport.ManagementApiUrl("http://username:password@localhost:15672"); -``` +For more details about the configuration, see [Configuring RabbitMQ delivery limit validation](/transports/rabbitmq/connection-settings?version=rabbit_10#configuring-rabbitmq-delivery-limit-validation). ### `IRoutingTopology` Updates From 8472bf0b5570d682794fe84e7b3e620c5b87ca3d Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Thu, 23 Jan 2025 11:38:55 -0800 Subject: [PATCH 5/9] Update snippet --- Snippets/Rabbit/Rabbit_10/Usage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Snippets/Rabbit/Rabbit_10/Usage.cs b/Snippets/Rabbit/Rabbit_10/Usage.cs index 9ea19cbdb74..42239183001 100644 --- a/Snippets/Rabbit/Rabbit_10/Usage.cs +++ b/Snippets/Rabbit/Rabbit_10/Usage.cs @@ -222,7 +222,7 @@ void SetManagementApiUrl(EndpointConfiguration endpointConfiguration) #region rabbitmq-management-api-url var transport = endpointConfiguration.UseTransport(); - transport.ManagementApiUrl("http(s)://{username}:{password}@{host}:{port}"); + transport.ManagementApiUrl("http://{username}:{password}@{host}:{port}"); #endregion } From c300aadda42e9a3b8362901ab962527fc15a76bf Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Thu, 23 Jan 2025 11:39:11 -0800 Subject: [PATCH 6/9] Fix link --- transports/upgrades/rabbitmq-9to10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transports/upgrades/rabbitmq-9to10.md b/transports/upgrades/rabbitmq-9to10.md index 2743eaf0e73..eafedadafa7 100644 --- a/transports/upgrades/rabbitmq-9to10.md +++ b/transports/upgrades/rabbitmq-9to10.md @@ -20,7 +20,7 @@ For details, see the [RabbitMQ client changelog](https://github.com/rabbitmq/rab The transport has introduced a client connection to the HTTP-based RabbitMQ management API. This requires the [rabbitmq management plugin](https://www.rabbitmq.com/docs/management#getting-started) to be enabled on the node. The client uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) to connect with the RabbitMQ management API and is configured via the `ManagementApiUrl` transport property. -For more details about the configuration, see [Configuring RabbitMQ delivery limit validation](/transports/rabbitmq/connection-settings?version=rabbit_10#configuring-rabbitmq-delivery-limit-validation). +For more details about the configuration, see [Configuring RabbitMQ delivery limit validation](/transports/rabbitmq/connection-settings.md?version=rabbit_10#configuring-rabbitmq-delivery-limit-validation). ### `IRoutingTopology` Updates From 99d321bd0aa68de0803c376ef97885f15d97c804 Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Thu, 23 Jan 2025 11:55:35 -0800 Subject: [PATCH 7/9] Add section about existing policies --- ...settings_management-api-url_rabbit_[10,).partial.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md index 9bb57dad116..d617c08d333 100644 --- a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md +++ b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md @@ -2,16 +2,20 @@ In RabbitMQ version 4.0 and above, queues are created with a default delivery limit of 20. However, for the NServiceBus recoverability process to function properly, the delivery limit should be set to unlimited (-1). -The RabbitMQ transport can verify that the RabbitMQ delivery limit is set to unlimited (-1) using the management API. This requires the [rabbitmq management plugin](https://www.rabbitmq.com/docs/management#getting-started) to be enabled on the RabbitMQ node. The management API uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) to connect. +The RabbitMQ transport can verify and set the RabbitMQ delivery limit to unlimited (-1) using the management API. This requires the [rabbitmq management plugin](https://www.rabbitmq.com/docs/management#getting-started) to be enabled on the RabbitMQ node. The management API uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) to connect. To configure the management API and perform the delivery limit validation, set the URL details as follows: snippet: rabbitmq-management-api-url > [!NOTE] -> If the management API URL is not set, the transport will use the credentials from the broker connection string and the default management API URL of `http://localhost:15672/api` to attempt to connect to the RabbitMQ management API. +> If the management API URL is not set, the transport will attempt to connect to the RabbitMQ management API with the default management API values based on the broker connection string. For example, if the broker connection string is `host=localhost;port=5672;useTls=true`, the management API would attempt to connect to `https://guest:guest@localhost:15671` . -The use of the management API and the validation of the delivery limit can be disabled by calling the `DoNotUseManagementApi()` transport method. +### Handling existing delivery limit policies + +If the RabbitMQ node already has a policy and the delivery limit is not set to unlimited (-1), the transport will raise an exception indicating that the RabbitMQ node already has a policy applied. The transport will not attempt to update the delivery limit of the existing policy or make a superseding delivery limit policy. + +Manually updating the delivery limit of an existing policy to unlimited (-1) or removing the existing policy will allow the management API to validate the delivery limit. If it's not feasible to update the delivery limit of an existing policy, the use of the management API and the validation of the delivery limit can be disabled by calling the `DoNotUseManagementApi()` transport method. > [!WARNING] > Potential message loss can occur if the delivery limit is not set to unlimited on the RabbitMQ node. If the delivery limit is not set to unlimited, the recoverability process may not function as intended. From 163e572a70161173844591ed754b761aedafb3ce Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Thu, 23 Jan 2025 11:58:40 -0800 Subject: [PATCH 8/9] Add snippet to rabbit_10 --- .../OutgoingNativeMessageCustomization.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 Snippets/Rabbit/Rabbit_10/OutgoingNativeMessageCustomization.cs diff --git a/Snippets/Rabbit/Rabbit_10/OutgoingNativeMessageCustomization.cs b/Snippets/Rabbit/Rabbit_10/OutgoingNativeMessageCustomization.cs new file mode 100644 index 00000000000..e236b441b60 --- /dev/null +++ b/Snippets/Rabbit/Rabbit_10/OutgoingNativeMessageCustomization.cs @@ -0,0 +1,23 @@ +using NServiceBus; + +class OutgoingNativeMessageCustomization +{ + OutgoingNativeMessageCustomization(EndpointConfiguration endpointConfiguration) + { + #region rabbitmq-customize-outgoing-message + + var rabbitMqTransport = new RabbitMQTransport( + routingTopology: RoutingTopology.Conventional(QueueType.Classic), + connectionString: "host=localhost;username=rabbitmq;password=rabbitmq", + enableDelayedDelivery: false + ); + + rabbitMqTransport.OutgoingNativeMessageCustomization = (operation, properties) => + { + //Set values on IBasicProperties + properties.ContentType = "application/my-type"; + }; + + #endregion + } +} \ No newline at end of file From 595f7ab45b2a9b7fb450bc420adfe318ff701641 Mon Sep 17 00:00:00 2001 From: Travis Nickels Date: Tue, 28 Jan 2025 21:07:20 -0800 Subject: [PATCH 9/9] Add ServiceControl upgrade guide and doc for rabbitMQ --- menu/menu.yaml | 2 ++ servicecontrol/transports.md | 5 +++++ servicecontrol/upgrades/6.2to6.3.md | 11 +++++++++++ ...ettings_management-api-url_rabbit_[10,).partial.md | 6 +++--- 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 servicecontrol/upgrades/6.2to6.3.md diff --git a/menu/menu.yaml b/menu/menu.yaml index fb43d346ff4..3927c0b0953 100644 --- a/menu/menu.yaml +++ b/menu/menu.yaml @@ -1426,6 +1426,8 @@ Articles: - Title: Upgrade tips Url: servicecontrol/upgrades + - Title: Version 6.2 to 6.3 + Url: servicecontrol/upgrades/6.2to6.3 - Title: Version 5 to 6 Url: servicecontrol/upgrades/5to6 - Title: Version 5.1 to 5.2 diff --git a/servicecontrol/transports.md b/servicecontrol/transports.md index 3a300d5e859..48922301196 100644 --- a/servicecontrol/transports.md +++ b/servicecontrol/transports.md @@ -67,6 +67,11 @@ In addition to the [connection string options of the transport](/transports/rabb * `UseExternalAuthMechanism=true|false(default)` - Specifies that an [external authentication mechanism should be used for client authentication](/transports/rabbitmq/connection-settings.md#transport-layer-security-support-external-authentication). * `DisableRemoteCertificateValidation=true|false(default)` - Allows ServiceControl to connect to the broker [even if the remote server certificate is invalid](/transports/rabbitmq/connection-settings.md#transport-layer-security-support-remote-certificate-validation). +These options are available for only quorum queues in version 6.3 and above: + +* `ManagementApiUri=` - The URI of the RabbitMQ management API. The default value is `http://guest:guest@localhost:15672/api/` +* `DisableManagemenApi=true|false(default)` - Disable the connection to the management API that is used to validate the delivery limit of quorum queues in RabbitMQ version 4 and above. + ## SQL In addition to the [connection string options of the transport](/transports/sql/connection-settings.md#connection-configuration) the following ServiceControl specific options are available in versions 4.4 and above: diff --git a/servicecontrol/upgrades/6.2to6.3.md b/servicecontrol/upgrades/6.2to6.3.md new file mode 100644 index 00000000000..735cbdf5676 --- /dev/null +++ b/servicecontrol/upgrades/6.2to6.3.md @@ -0,0 +1,11 @@ +--- +title: Upgrade ServiceControl from Version 6.2.x to Version 6.3.x +summary: Instructions on how to upgrade ServiceControl from version 6.2.x to 6.3.x +reviewed: 2025-01-28 +isUpgradeGuide: true +component: ServiceControl +--- + +## RabbitMQ delivery limit validation + +ServiceControl version 6.3 uses rabbitMQ transport version 10.x. When using RabbitMQ 4 and above the management API is required as part of the transport to validate the delivery limit of the queue to insure that it's set to unlimited (-1) for proper recoverability functionality. The [management API plugin](https://www.rabbitmq.com/docs/management#getting-started) is required to be installed on the node. If the configuration of the management API is different than the default values based on the broker connection string, then the connection can be configured using the [RabbitMQ transport configuration options](/servicecontrol/transports.md#rabbitmq). diff --git a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md index d617c08d333..ee8a760d5e1 100644 --- a/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md +++ b/transports/rabbitmq/connection-settings_management-api-url_rabbit_[10,).partial.md @@ -9,13 +9,13 @@ To configure the management API and perform the delivery limit validation, set t snippet: rabbitmq-management-api-url > [!NOTE] -> If the management API URL is not set, the transport will attempt to connect to the RabbitMQ management API with the default management API values based on the broker connection string. For example, if the broker connection string is `host=localhost;port=5672;useTls=true`, the management API would attempt to connect to `https://guest:guest@localhost:15671` . +> If the management API URL is not set, the transport will attempt to connect to the RabbitMQ management API with the default management API values based on the broker connection string. For example, if the broker connection string is `host=localhost;port=5671;useTls=true`, the management API would attempt to connect to `https://guest:guest@localhost:15671` . ### Handling existing delivery limit policies -If the RabbitMQ node already has a policy and the delivery limit is not set to unlimited (-1), the transport will raise an exception indicating that the RabbitMQ node already has a policy applied. The transport will not attempt to update the delivery limit of the existing policy or make a superseding delivery limit policy. +If a queue already has a policy and the delivery limit is not set to unlimited (-1), the transport will raise an exception indicating that the RabbitMQ node already has a policy applied. The transport will not attempt to update the delivery limit of the existing policy or make a superseding delivery limit policy. Manually updating the delivery limit of an existing policy to unlimited (-1) or removing the existing policy will allow the management API to validate the delivery limit. If it's not feasible to update the delivery limit of an existing policy, the use of the management API and the validation of the delivery limit can be disabled by calling the `DoNotUseManagementApi()` transport method. > [!WARNING] -> Potential message loss can occur if the delivery limit is not set to unlimited on the RabbitMQ node. If the delivery limit is not set to unlimited, the recoverability process may not function as intended. +> Potential message loss can occur if the delivery limit is not set to unlimited on the queue. If the delivery limit is not set to unlimited, the recoverability process may not function as intended.