Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RabbitMQ.Stream.Client/IAddressResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 2.0, and the Mozilla Public License, version 2.0.
// Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.

using System;
using System.Net;
using System.Threading.Tasks;

Expand All @@ -10,5 +11,9 @@ namespace RabbitMQ.Stream.Client;
public interface IAddressResolver
{
public bool Enabled { get; }

[Obsolete("Deprecated. Use ResolveAsync instead.")]
public EndPoint Resolve(string address, int port);

public Task<EndPoint> ResolveAsync(string address, int port);
}
1 change: 1 addition & 0 deletions RabbitMQ.Stream.Client/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ RabbitMQ.Stream.Client.HashRoutingMurmurStrategy.Route(RabbitMQ.Stream.Client.Me
RabbitMQ.Stream.Client.HeartBeatHandler.HeartBeatHandler(System.Func<System.Threading.Tasks.ValueTask<bool>> sendHeartbeatFunc, System.Func<string, string, System.Threading.Tasks.Task<RabbitMQ.Stream.Client.CloseResponse>> close, int heartbeat, Microsoft.Extensions.Logging.ILogger<RabbitMQ.Stream.Client.HeartBeatHandler> logger = null) -> void
RabbitMQ.Stream.Client.IAddressResolver
RabbitMQ.Stream.Client.IAddressResolver.Enabled.get -> bool
RabbitMQ.Stream.Client.IAddressResolver.Resolve(string address, int port) -> System.Net.EndPoint
RabbitMQ.Stream.Client.IAddressResolver.ResolveAsync(string address, int port) -> System.Threading.Tasks.Task<System.Net.EndPoint>
RabbitMQ.Stream.Client.IClient.ClientId.get -> string
RabbitMQ.Stream.Client.IClient.ClientId.init -> void
Expand Down
22 changes: 22 additions & 0 deletions docs/Documentation/StreamSystemUsage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,28 @@ private static async Task CreateAddressResolver()
await streamSystem.Close().ConfigureAwait(false);
}
// end::create-address-resolver[]


// tag::create-dsn-address-resolver[]
private static async Task CreateDnsAddressResolver()
{
var dnsResolver = new DnsAddressResolver(new DnsEndPoint("rabbitmq-stream.my-cluster.local", 5552)); // <1>

var streamSystem = await StreamSystem.Create(
new StreamSystemConfig()
{
UserName = "myuser",
Password = "mypassword",
AddressResolver = dnsResolver, // <2>
Endpoints = new List<EndPoint> {dnsResolver.EndPoint} // <3>
}
).ConfigureAwait(false);


await streamSystem.Close().ConfigureAwait(false);
}
// end::create-dns-address-resolver[]


// tag::stream-creation[]
private static async Task CreateStream()
Expand Down
27 changes: 15 additions & 12 deletions docs/asciidoc/api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -307,32 +307,35 @@ The blog post covers the https://blog.rabbitmq.com/posts/2021/07/connecting-to-s
[[dns-address-resolver]]
====== Using DNS Round-Robin Instead of a Load Balancer

Starting from version 1.12 (https://github.com/rabbitmq/rabbitmq-stream-dotnet-client/pull/466[#466]), the client ships a built-in `DnsAddressResolver` that relies on DNS round-robin instead of a dedicated load balancer.
`DnsAddressResolver` relies on DNS round-robin instead of a dedicated load balancer.

This is useful when the cluster nodes are exposed behind a single DNS name that resolves to multiple `A`/`AAAA` records (for example a Kubernetes headless service or a DNS-based service discovery setup). Instead of routing every connection through a load balancer, the client resolves the DNS name on each connection attempt and picks one of the returned IP addresses, distributing connections across the cluster nodes.

`DnsAddressResolver` implements `IAddressResolver`, so it can be assigned directly to `StreamSystemConfig#AddressResolver`:

.Using the DNS address resolver
[source,c#,indent=0]
--------
var dnsResolver = new DnsAddressResolver(new DnsEndPoint("rabbitmq-stream.my-cluster.local", 5552)); // <1>

var streamSystem = await StreamSystem.Create(
new StreamSystemConfig
{
AddressResolver = dnsResolver, // <2>
Endpoints = new List<EndPoint> { dnsResolver.EndPoint } // <3>
}).ConfigureAwait(false);
--------
include::{test-examples}/StreamSystemUsage.cs[tag=create-dsn-address-resolver]

<1> Create the resolver with the `DnsEndPoint` (host and port) shared by all cluster nodes
<2> Use the DNS resolver to resolve node addresses before each connection
<3> Use the same endpoint for the initial locator connection

On every connection the resolver calls `ResolveAsync(...)`, which performs a DNS lookup of the configured host and returns one of the resolved IP addresses, achieving round-robin distribution across the nodes the DNS name points to.

NOTE: `DnsAddressResolver` ignores the per-node metadata hints returned by the broker, exactly like the custom load-balancer resolver above. The difference is that the node selection is driven by DNS resolution rather than by a load balancer.
NOTE: `DnsAddressResolver` ignores the per-node metadata hints returned by the broker, exactly like the custom load-balancer resolver above.
The difference is that the node selection is driven by DNS resolution rather than by a load balancer.

You can use tour own implementation of `IAddressResolver` to implement custom address resolution strategies,
for example based on service discovery or other mechanisms.

[NOTE]
.IAddressResolver Derepcation
====
Starting from version 1.12.0 the `Resolve` field is deprecated.
Use `ResolveAsync` instead.
====


===== Managing Streams

Expand Down
Loading