/// <summary> /// Retrieves the next reachable <see cref="RemoteHost"/>. /// </summary> /// <param name="affinityToken"> /// A string to generate a consistent affinity to a specific host within the set of available hosts. /// Identical strings will return the same host for a given pool of reachable hosts. A request ID is usually provided. /// </param> /// <returns>A reachable <see cref="RemoteHost"/>.</returns> /// <exception cref="EnvironmentException">Thrown when there is no reachable <see cref="RemoteHost"/> available.</exception> public IEndPointHandle GetNextHost(string affinityToken = null) { LastEndpointRequest = DateTime.UtcNow; var hostOverride = TracingContext.GetHostOverride(DeploymentIdentifier.ServiceName); if (hostOverride != null) { return(new OverriddenRemoteHost(DeploymentIdentifier.ServiceName, hostOverride.Hostname, hostOverride.Port ?? GetConfig().DefaultPort)); } lock (_lock) { Health.Activate(); if (ReachableHosts.Count == 0) { var lastExceptionEndPoint = UnreachableHosts.FirstOrDefault(); // TODO: Exception throwing code should be in this class, not in another. throw DiscoverySource.AllEndpointsUnreachable(EndPointsResult, lastExceptionEndPoint?.LastException, lastExceptionEndPoint == null ? null : $"{lastExceptionEndPoint.HostName}:{lastExceptionEndPoint.Port}", string.Join(", ", UnreachableHosts)); } Counter++; ulong hostId = affinityToken == null ? Counter : (ulong)affinityToken.GetHashCode(); return(ReachableHosts[(int)(hostId % (ulong)ReachableHosts.Count)]); } }