@@ -157,13 +157,6 @@ public class ConnectionFactory : ConnectionFactoryBase, IConnectionFactory
157
157
/// </summary>
158
158
public bool AutomaticRecoveryEnabled { get ; set ; }
159
159
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 { get ; set ; } = new RandomHostnameSelector ( ) ;
166
-
167
160
/// <summary>The host to connect to.</summary>
168
161
public string HostName { get ; set ; } = "localhost" ;
169
162
@@ -194,6 +187,17 @@ public TimeSpan ContinuationTimeout
194
187
set { m_continuationTimeout = value ; }
195
188
}
196
189
190
+ /// <summary>
191
+ /// Factory function for creating the <see cref="IEndpointResolver">
192
+ /// used to generate a list of endpoints for the ConnectionFactory
193
+ /// to try in order.
194
+ /// The default value creates an instance of the <see cref="DefaultEndpointResolver">
195
+ /// using the list of endpoints passed in. The DefaultEndpointResolver shuffles the
196
+ /// provided list each time it is requested.
197
+ /// </summary>
198
+ public Func < IEnumerable < AmqpTcpEndpoint > , IEndpointResolver > EndpointResolverFactory { get ; set ; } =
199
+ endpoints => new DefaultEndpointResolver ( endpoints ) ;
200
+
197
201
/// <summary>
198
202
/// The port to connect on. <see cref="AmqpTcpEndpoint.UseDefaultPort"/>
199
203
/// indicates the default for the protocol should be used.
@@ -258,6 +262,7 @@ public AmqpTcpEndpoint Endpoint
258
262
}
259
263
}
260
264
265
+
261
266
/// <summary>
262
267
/// Set connection parameters using the amqp or amqps scheme.
263
268
/// </summary>
@@ -333,18 +338,22 @@ public AuthMechanismFactory AuthMechanismFactory(IList<string> mechanismNames)
333
338
}
334
339
335
340
/// <summary>
336
- /// Create a connection to the specified endpoint.
341
+ /// Create a connection to one of the endpoints provided by the IEndpointResolver
342
+ /// returned by the EndpointResolverFactory. By default the configured
343
+ /// hostname and port are used.
337
344
/// </summary>
338
345
/// <exception cref="BrokerUnreachableException">
339
346
/// When the configured hostname was not reachable.
340
347
/// </exception>
341
348
public virtual IConnection CreateConnection ( )
342
349
{
343
- return CreateConnection ( new List < string > { HostName } , null ) ;
350
+ return CreateConnection ( this . EndpointResolverFactory ( LocalEndpoints ( ) ) , null ) ;
344
351
}
345
352
346
353
/// <summary>
347
- /// Create a connection to the specified endpoint.
354
+ /// Create a connection to one of the endpoints provided by the IEndpointResolver
355
+ /// returned by the EndpointResolverFactory. By default the configured
356
+ /// hostname and port are used.
348
357
/// </summary>
349
358
/// <param name="clientProvidedName">
350
359
/// Application-specific connection name, will be displayed in the management UI
@@ -357,13 +366,14 @@ public virtual IConnection CreateConnection()
357
366
/// </exception>
358
367
public IConnection CreateConnection ( String clientProvidedName )
359
368
{
360
- return CreateConnection ( new List < string > { HostName } , clientProvidedName ) ;
369
+ return CreateConnection ( EndpointResolverFactory ( LocalEndpoints ( ) ) , clientProvidedName ) ;
361
370
}
362
371
363
372
/// <summary>
364
- /// Create a connection using a list of hostnames. The first reachable
365
- /// hostname will be used initially. Subsequent hostname picks are determined
366
- /// by the <see cref="IHostnameSelector" /> configured.
373
+ /// Create a connection using a list of hostnames using the configured port.
374
+ /// By default each hostname is tried in a random order until a successful connection is
375
+ /// found or the list is exhausted using the DefaultEndpointResolver.
376
+ /// The selection behaviour can be overriden by configuring the EndpointResolverFactory.
367
377
/// </summary>
368
378
/// <param name="hostnames">
369
379
/// List of hostnames to use for the initial
@@ -379,9 +389,10 @@ public IConnection CreateConnection(IList<string> hostnames)
379
389
}
380
390
381
391
/// <summary>
382
- /// Create a connection using a list of hostnames. The first reachable
383
- /// hostname will be used initially. Subsequent hostname picks are determined
384
- /// by the <see cref="IHostnameSelector" /> configured.
392
+ /// Create a connection using a list of hostnames using the configured port.
393
+ /// By default each endpoint is tried in a random order until a successful connection is
394
+ /// found or the list is exhausted.
395
+ /// The selection behaviour can be overriden by configuring the EndpointResolverFactory.
385
396
/// </summary>
386
397
/// <param name="hostnames">
387
398
/// List of hostnames to use for the initial
@@ -399,13 +410,14 @@ public IConnection CreateConnection(IList<string> hostnames)
399
410
/// </exception>
400
411
public IConnection CreateConnection ( IList < string > hostnames , String clientProvidedName )
401
412
{
402
- return CreateConnection ( hostnames . Select ( Endpoint . CloneWithHostname ) . ToList ( ) , clientProvidedName ) ;
413
+ var endpoints = hostnames . Select ( h => new AmqpTcpEndpoint ( h , this . Port , this . Ssl ) ) ;
414
+ return CreateConnection ( new DefaultEndpointResolver ( endpoints ) , clientProvidedName ) ;
403
415
}
404
416
405
417
/// <summary>
406
- /// Create a connection using a list of hostnames. The first reachable
407
- /// hostname will be used initially. Subsequent hostname picks are determined
408
- /// by the <see cref="IHostnameSelector" /> configured .
418
+ /// Create a connection using a list of endpoints. By default each endpoint will be tried
419
+ /// in a random order until a successful connection is found or the list is exhausted.
420
+ /// The selection behaviour can be overriden by configuring the EndpointResolverFactory .
409
421
/// </summary>
410
422
/// <param name="endpoints">
411
423
/// List of endpoints to use for the initial
@@ -417,17 +429,14 @@ public IConnection CreateConnection(IList<string> hostnames, String clientProvid
417
429
/// </exception>
418
430
public IConnection CreateConnection ( IList < AmqpTcpEndpoint > endpoints )
419
431
{
420
- return CreateConnection ( endpoints , null ) ;
432
+ return CreateConnection ( new DefaultEndpointResolver ( endpoints ) , null ) ;
421
433
}
422
434
423
435
/// <summary>
424
- /// Create a connection using a list of hostnames. The first reachable
425
- /// hostname will be used initially. Subsequent hostname picks are determined
426
- /// by the <see cref="IHostnameSelector" /> configured.
436
+ /// Create a connection using an IEndpointResolver.
427
437
/// </summary>
428
- /// <param name="endpoints">
429
- /// List of endpoints to use for the initial
430
- /// connection and recovery.
438
+ /// <param name="endpointResolver">
439
+ /// The endpointResolver that returns the endpoints to use for the connection attempt.
431
440
/// </param>
432
441
/// <param name="clientProvidedName">
433
442
/// Application-specific connection name, will be displayed in the management UI
@@ -439,32 +448,28 @@ public IConnection CreateConnection(IList<AmqpTcpEndpoint> endpoints)
439
448
/// <exception cref="BrokerUnreachableException">
440
449
/// When no hostname was reachable.
441
450
/// </exception>
442
- public IConnection CreateConnection ( IList < AmqpTcpEndpoint > endpoints , String clientProvidedName )
451
+ public IConnection CreateConnection ( IEndpointResolver endpointResolver , String clientProvidedName )
443
452
{
444
- var eps = endpoints . ToList ( ) ;
445
453
IConnection conn ;
446
454
try
447
455
{
448
456
if ( AutomaticRecoveryEnabled )
449
457
{
450
458
var autorecoveringConnection = new AutorecoveringConnection ( this , clientProvidedName ) ;
451
- autorecoveringConnection . Init ( eps ) ;
459
+ autorecoveringConnection . Init ( endpointResolver ) ;
452
460
conn = autorecoveringConnection ;
453
461
}
454
462
else
455
463
{
456
464
IProtocol protocol = Protocols . DefaultProtocol ;
457
- //We can't make this more elegant without changing the contract of the IHostnameSelector
458
- //if there are endpoints with the same hostname but different ports the first match is selected
459
- var selectedHost = HostnameSelector . NextFrom ( eps . Select ( ep => ep . HostName ) . ToList ( ) ) ;
460
- var selectedEndpoint = eps . First ( ep => ep . HostName == selectedHost ) ;
461
- conn = protocol . CreateConnection ( this , false , CreateFrameHandler ( selectedEndpoint ) , clientProvidedName ) ;
465
+ conn = protocol . CreateConnection ( this , false , endpointResolver . SelectOne ( this . CreateFrameHandler ) , clientProvidedName ) ;
462
466
}
463
467
}
464
468
catch ( Exception e )
465
469
{
466
470
throw new BrokerUnreachableException ( e ) ;
467
471
}
472
+
468
473
return conn ;
469
474
}
470
475
@@ -566,5 +571,10 @@ private static string UriDecode(string uri)
566
571
{
567
572
return System . Uri . UnescapeDataString ( uri . Replace ( "+" , "%2B" ) ) ;
568
573
}
574
+
575
+ private List < AmqpTcpEndpoint > LocalEndpoints ( )
576
+ {
577
+ return new List < AmqpTcpEndpoint > { this . Endpoint } ;
578
+ }
569
579
}
570
580
}
0 commit comments