/// <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)]); } }
private ValueTask <HealthCheckResult> CheckHealth() { var config = GetConfig(); if (IsHealthCheckSuppressed(config)) { return(new ValueTask <HealthCheckResult>(HealthCheckResult.Healthy($"Health check suppressed because service was not in use for more than {config.SuppressHealthCheckAfterServiceUnused.TotalSeconds} seconds."))); } int reachableCount; int unreachableCount; Exception exception; string[] unreachableHosts; lock (_lock) { reachableCount = ReachableHosts.Count; unreachableHosts = UnreachableHosts.Select(x => $"{x.HostName}:{x.Port}").ToArray(); unreachableCount = unreachableHosts.Length; exception = UnreachableHosts.FirstOrDefault()?.LastException; } if (reachableCount == 0) { return(new ValueTask <HealthCheckResult>(HealthCheckResult.Unhealthy($"All of the {unreachableCount} hosts are unreachable: " + $"{string.Join(",", unreachableHosts)}. Last exception: {HealthMonitor.GetMessages(exception)}"))); } else { if (unreachableCount > 0) { return(new ValueTask <HealthCheckResult>(HealthCheckResult.Unhealthy($"The following {unreachableCount} hosts " + $"(out of {unreachableCount + reachableCount}) are unreachable: {string.Join(",", unreachableHosts)}. " + $"Last exception: {HealthMonitor.GetMessages(exception)}"))); } else { return(new ValueTask <HealthCheckResult>(HealthCheckResult.Healthy($"All {reachableCount} hosts are reachable."))); } } }