diff --git a/.azure/pipelines/azure-pipelines-external-release.yml b/.azure/pipelines/azure-pipelines-external-release.yml index 579d1b5239..1a593b40a9 100644 --- a/.azure/pipelines/azure-pipelines-external-release.yml +++ b/.azure/pipelines/azure-pipelines-external-release.yml @@ -169,7 +169,7 @@ jobs: inputs: action: 'create' gitHubConnection: ADO_to_Github_ServiceConnection - tagSource: manual + tagSource: userSpecifiedTag tag: 'v$(Build.BuildNumber)' title: 'Garnet v$(Build.BuildNumber)' releaseNotesSource: input diff --git a/libs/client/GarnetClient.cs b/libs/client/GarnetClient.cs index 2edabf7627..dcd976a7e6 100644 --- a/libs/client/GarnetClient.cs +++ b/libs/client/GarnetClient.cs @@ -188,7 +188,7 @@ public GarnetClient( /// public void Connect(CancellationToken token = default) { - socket = GetSendSocket(timeoutMilliseconds); + socket = CreateSendSocket(timeoutMilliseconds); networkWriter = new NetworkWriter(this, socket, bufferSize, sslOptions, out networkHandler, sendPageSize, networkSendThrottleMax, logger); networkHandler.StartAsync(sslOptions, $"{address}:{port}", token).ConfigureAwait(false).GetAwaiter().GetResult(); networkSender = networkHandler.GetNetworkSender(); @@ -221,7 +221,7 @@ public void Connect(CancellationToken token = default) /// public async Task ConnectAsync(CancellationToken token = default) { - socket = GetSendSocket(timeoutMilliseconds); + socket = CreateSendSocket(timeoutMilliseconds); networkWriter = new NetworkWriter(this, socket, bufferSize, sslOptions, out networkHandler, sendPageSize, networkSendThrottleMax, logger); await networkHandler.StartAsync(sslOptions, $"{address}:{port}", token).ConfigureAwait(false); networkSender = networkHandler.GetNetworkSender(); @@ -249,37 +249,86 @@ public async Task ConnectAsync(CancellationToken token = default) } } - Socket GetSendSocket(int millisecondsTimeout = 0) + /// + /// Create client send socket + /// + /// + /// + /// + Socket CreateSendSocket(int millisecondsTimeout = 0) { - var ip = IPAddress.Parse(address); - var endPoint = new IPEndPoint(ip, port); + if (!IPAddress.TryParse(address, out var ip)) + { + var hostEntries = Dns.GetHostEntry(address); + // Try all available DNS entries if a hostName is provided + foreach (var addressEntry in hostEntries.AddressList) + { + var endPoint = new IPEndPoint(addressEntry, port); + if (!TryConnectSocket(endPoint, millisecondsTimeout, out var socket)) + continue; + return socket; + } + + // Reaching this point means we failed to establish connection from any of the provided addresses + throw new Exception($"Failed to connect at {address}:{port}"); + } + else + { + var endPoint = new IPEndPoint(ip, port); + if (!TryConnectSocket(endPoint, millisecondsTimeout, out var socket)) + { + // If failed here then provided endpoint does not accept connections + logger?.LogWarning("Failed to connect at {address}:{port}", ip.ToString(), port); + throw new Exception($"Failed to connect at {ip.ToString()}:{port}"); + } + return socket; + } + } - var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) + /// + /// Try to establish connection for socket using endPoint + /// + /// + /// + /// + /// + bool TryConnectSocket(IPEndPoint endPoint, int millisecondsTimeout, out Socket socket) + { + socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; - - if (millisecondsTimeout > 0) + try { - var result = socket.BeginConnect(endPoint, null, null); - result.AsyncWaitHandle.WaitOne(millisecondsTimeout, true); - - if (socket.Connected) + if (millisecondsTimeout > 0) { - socket.EndConnect(result); + var result = socket.BeginConnect(endPoint, null, null); + result.AsyncWaitHandle.WaitOne(millisecondsTimeout, true); + + if (socket.Connected) + { + socket.EndConnect(result); + } + else + { + socket.Close(); + throw new Exception($"Failed to connect server {address}:{port}."); + } } else { - socket.Close(); - throw new Exception($"Failed to connect server {address}:{port}."); + socket.Connect(endPoint); } } - else + catch (Exception ex) { - socket.Connect(endPoint); + logger?.LogWarning(ex, "Failed at GarnetClient.TryConnectSocket"); + socket.Dispose(); + socket = null; + return false; } - return socket; + return true; } async Task TimeoutChecker()