Skip to content

Commit 5b29d16

Browse files
Merge pull request #92 from rabbitmq/rabbitmq-dotnet-client-81
Introduce ConnectionFactory#CreateConnection with a list of hostnames
2 parents e600fdf + cd31f99 commit 5b29d16

14 files changed

+411
-80
lines changed

projects/client/RabbitMQ.Client/RabbitMQ.Client.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
<Compile Include="src\client\api\IConnection.cs" />
140140
<Compile Include="src\client\api\IConnectionFactory.cs" />
141141
<Compile Include="src\client\api\IContentHeader.cs" />
142+
<Compile Include="src\client\api\IHostnameSelector.cs" />
142143
<Compile Include="src\client\api\IMethod.cs" />
143144
<Compile Include="src\client\api\IModel.cs" />
144145
<Compile Include="src\client\api\IProtocol.cs" />
@@ -216,6 +217,7 @@
216217
<Compile Include="src\client\impl\ContentHeaderBase.cs" />
217218
<Compile Include="src\client\impl\ContentHeaderPropertyReader.cs" />
218219
<Compile Include="src\client\impl\ContentHeaderPropertyWriter.cs" />
220+
<Compile Include="src\client\impl\ExtensionMethods.cs" />
219221
<Compile Include="src\client\impl\Frame.cs" />
220222
<Compile Include="src\client\impl\HardProtocolException.cs" />
221223
<Compile Include="src\client\impl\IConsumerDispatcher.cs" />
@@ -232,6 +234,7 @@
232234
<Compile Include="src\client\impl\ProtocolBase.cs" />
233235
<Compile Include="src\client\impl\ProtocolException.cs" />
234236
<Compile Include="src\client\impl\QuiescingSession.cs" />
237+
<Compile Include="src\client\impl\RandomHostnameSelector.cs" />
235238
<Compile Include="src\client\impl\RecordedBinding.cs" />
236239
<Compile Include="src\client\impl\RecordedConsumer.cs" />
237240
<Compile Include="src\client\impl\RecordedEntity.cs" />

projects/client/RabbitMQ.Client/src/client/api/AmqpTcpEndpoint.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ namespace RabbitMQ.Client
5555
/// the Uri "Scheme" property is ignored: only the "Host" and
5656
/// "Port" properties are extracted.
5757
/// </para>
58-
public class AmqpTcpEndpoint
58+
public class AmqpTcpEndpoint : ICloneable
5959
{
6060
/// <summary>
6161
/// Default Amqp ssl port.
@@ -119,6 +119,25 @@ public AmqpTcpEndpoint(Uri uri) : this(uri.Host, uri.Port)
119119
{
120120
}
121121

122+
/// <summary>
123+
/// Clones the endpoint.
124+
/// </summary>
125+
/// <returns>A copy with the same hostname, port, and TLS settings</returns>
126+
public object Clone()
127+
{
128+
return new AmqpTcpEndpoint(HostName, _port, Ssl);
129+
}
130+
131+
/// <summary>
132+
/// Clones the endpoint using the provided hostname.
133+
/// </summary>
134+
/// <param name="hostname">Hostname to use</param>
135+
/// <returns>A copy with the provided hostname and port/TLS settings of this endpoint</returns>
136+
public AmqpTcpEndpoint CloneWithHostname(string hostname)
137+
{
138+
return new AmqpTcpEndpoint(hostname, _port, Ssl);
139+
}
140+
122141
/// <summary>
123142
/// Retrieve or set the hostname of this <see cref="AmqpTcpEndpoint"/>.
124143
/// </summary>

projects/client/RabbitMQ.Client/src/client/api/ConnectionFactory.cs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
using System;
4545
using System.Collections.Generic;
4646
using System.Threading.Tasks;
47+
using System.Linq;
4748

4849
#if !NETFX_CORE
4950

@@ -143,18 +144,26 @@ public class ConnectionFactory : ConnectionFactoryBase, IConnectionFactory
143144
/// <summary>
144145
/// Default SASL auth mechanisms to use.
145146
/// </summary>
146-
public static readonly AuthMechanismFactory[] DefaultAuthMechanisms = { new PlainMechanismFactory() };
147+
public static readonly IList<AuthMechanismFactory> DefaultAuthMechanisms =
148+
new List<AuthMechanismFactory>(){ new PlainMechanismFactory() };
147149

148150
/// <summary>
149151
/// SASL auth mechanisms to use.
150152
/// </summary>
151-
public AuthMechanismFactory[] AuthMechanisms = DefaultAuthMechanisms;
153+
public IList<AuthMechanismFactory> AuthMechanisms = DefaultAuthMechanisms;
152154

153155
/// <summary>
154156
/// Set to true to enable automatic connection recovery.
155157
/// </summary>
156158
public bool AutomaticRecoveryEnabled;
157159

160+
/// <summary>
161+
/// Used to select next hostname to try when performing
162+
/// connection recovery (re-connecting). Is not used for
163+
/// non-recovering connections.
164+
/// </summary>
165+
public IHostnameSelector HostnameSelector = new RandomHostnameSelector();
166+
158167
/// <summary>The host to connect to.</summary>
159168
public String HostName = "localhost";
160169

@@ -212,7 +221,7 @@ public ConnectionFactory()
212221
}
213222

214223
/// <summary>
215-
/// The AMQP connection target.
224+
/// Connection endpoint.
216225
/// </summary>
217226
public AmqpTcpEndpoint Endpoint
218227
{
@@ -285,12 +294,12 @@ public Uri uri
285294
/// Given a list of mechanism names supported by the server, select a preferred mechanism,
286295
/// or null if we have none in common.
287296
/// </summary>
288-
public AuthMechanismFactory AuthMechanismFactory(string[] mechanismNames)
297+
public AuthMechanismFactory AuthMechanismFactory(IList<string> mechanismNames)
289298
{
290299
// Our list is in order of preference, the server one is not.
291300
foreach (AuthMechanismFactory factory in AuthMechanisms)
292301
{
293-
if (Array.Exists(mechanismNames, x => string.Equals(x, factory.Name, StringComparison.OrdinalIgnoreCase)))
302+
if (mechanismNames.Any<string>(x => string.Equals(x, factory.Name, StringComparison.OrdinalIgnoreCase)))
294303
{
295304
return factory;
296305
}
@@ -301,35 +310,59 @@ public AuthMechanismFactory AuthMechanismFactory(string[] mechanismNames)
301310
/// <summary>
302311
/// Create a connection to the specified endpoint.
303312
/// </summary>
313+
/// <exception cref="BrokerUnreachableException">
314+
/// When the configured hostname was not reachable.
315+
/// </exception>
304316
public virtual IConnection CreateConnection()
305317
{
306-
IConnection connection;
318+
return CreateConnection(new List<string>() { HostName });
319+
}
320+
321+
/// <summary>
322+
/// Create a connection using a list of hostnames. The first reachable
323+
/// hostname will be used initially. Subsequent hostname picks are determined
324+
/// by the <see cref="IHostnameSelector" /> configured.
325+
/// </summary>
326+
/// <param name="hostnames">
327+
/// List of hostnames to use for the initial
328+
/// connection and recovery.
329+
/// </param>
330+
/// <returns>Open connection</returns>
331+
/// <exception cref="BrokerUnreachableException">
332+
/// When no hostname was reachable.
333+
/// </exception>
334+
public IConnection CreateConnection(IList<string> hostnames)
335+
{
336+
IConnection conn;
307337
try
308338
{
309339
if (AutomaticRecoveryEnabled)
310340
{
311341
var autorecoveringConnection = new AutorecoveringConnection(this);
312-
autorecoveringConnection.init();
313-
connection = autorecoveringConnection;
342+
autorecoveringConnection.Init(hostnames);
343+
conn = autorecoveringConnection;
314344
}
315345
else
316346
{
317347
IProtocol protocol = Protocols.DefaultProtocol;
318-
connection = protocol.CreateConnection(this, false, CreateFrameHandler());
348+
conn = protocol.CreateConnection(this, false, CreateFrameHandler());
319349
}
320350
}
321351
catch (Exception e)
322352
{
323353
throw new BrokerUnreachableException(e);
324354
}
325-
326-
return connection;
355+
return conn;
327356
}
328357

329358
public IFrameHandler CreateFrameHandler()
330359
{
331-
IProtocol protocol = Protocols.DefaultProtocol;
332-
return protocol.CreateFrameHandler(Endpoint, SocketFactory, RequestedConnectionTimeout);
360+
return Protocols.DefaultProtocol.CreateFrameHandler(Endpoint, SocketFactory, RequestedConnectionTimeout);
361+
}
362+
363+
public IFrameHandler CreateFrameHandler(AmqpTcpEndpoint endpoint)
364+
{
365+
return Protocols.DefaultProtocol.CreateFrameHandler(endpoint, SocketFactory, RequestedConnectionTimeout);
333366
}
334367

335368
private void SetUri(Uri uri)

projects/client/RabbitMQ.Client/src/client/api/IConnectionFactory.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,20 @@ public interface IConnectionFactory
9090
/// Given a list of mechanism names supported by the server, select a preferred mechanism,
9191
/// or null if we have none in common.
9292
/// </summary>
93-
AuthMechanismFactory AuthMechanismFactory(string[] mechanismNames);
93+
AuthMechanismFactory AuthMechanismFactory(IList<string> mechanismNames);
9494

9595
/// <summary>
9696
/// Create a connection to the specified endpoint.
9797
/// </summary>
9898
IConnection CreateConnection();
9999

100+
/// <summary>
101+
/// Connects to the first reachable hostname from the list.
102+
/// </summary>
103+
/// <param name="hostnames">List of host names to use</param>
104+
/// <returns></returns>
105+
IConnection CreateConnection(IList<string> hostnames);
106+
100107
/// <summary>
101108
/// Advanced option.
102109
///
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// This source code is dual-licensed under the Apache License, version
2+
// 2.0, and the Mozilla Public License, version 1.1.
3+
//
4+
// The APL v2.0:
5+
//
6+
//---------------------------------------------------------------------------
7+
// Copyright (C) 2007-2014 GoPivotal, Inc.
8+
//
9+
// Licensed under the Apache License, Version 2.0 (the "License");
10+
// you may not use this file except in compliance with the License.
11+
// You may obtain a copy of the License at
12+
//
13+
// http://www.apache.org/licenses/LICENSE-2.0
14+
//
15+
// Unless required by applicable law or agreed to in writing, software
16+
// distributed under the License is distributed on an "AS IS" BASIS,
17+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
// See the License for the specific language governing permissions and
19+
// limitations under the License.
20+
//---------------------------------------------------------------------------
21+
//
22+
// The MPL v1.1:
23+
//
24+
//---------------------------------------------------------------------------
25+
// The contents of this file are subject to the Mozilla Public License
26+
// Version 1.1 (the "License"); you may not use this file except in
27+
// compliance with the License. You may obtain a copy of the License
28+
// at http://www.mozilla.org/MPL/
29+
//
30+
// Software distributed under the License is distributed on an "AS IS"
31+
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
32+
// the License for the specific language governing rights and
33+
// limitations under the License.
34+
//
35+
// The Original Code is RabbitMQ.
36+
//
37+
// The Initial Developer of the Original Code is GoPivotal, Inc.
38+
// Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved.
39+
//---------------------------------------------------------------------------
40+
41+
using System;
42+
using System.Collections.Generic;
43+
44+
namespace RabbitMQ.Client
45+
{
46+
public interface IHostnameSelector
47+
{
48+
/// <summary>
49+
/// Picks a hostname from a list of options that should be used
50+
/// by <see cref="IConnectionFactory"/>.
51+
/// </summary>
52+
/// <param name="options"></param>
53+
/// <returns></returns>
54+
string NextFrom(IList<string> options);
55+
}
56+
}

projects/client/RabbitMQ.Client/src/client/api/NetworkConnection.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,11 @@ namespace RabbitMQ.Client
4747
/// </summary>
4848
public interface NetworkConnection
4949
{
50-
#if !NETFX_CORE
51-
/// <summary>
52-
/// Identifies local network address.
53-
/// </summary>
54-
EndPoint LocalEndPoint { get; }
55-
#endif
56-
5750
/// <summary>
5851
/// Local port.
5952
/// </summary>
6053
int LocalPort { get; }
6154

62-
#if !NETFX_CORE
63-
/// <summary>
64-
/// Identifies remote network address.
65-
/// </summary>
66-
EndPoint RemoteEndPoint { get; }
67-
#endif
68-
6955
/// <summary>
7056
/// Remote port.
7157
/// </summary>

0 commit comments

Comments
 (0)