// internal methods internal void Connect(TimeSpan timeout) { var exceptions = new List<Exception>(); foreach (var address in server.Settings.Servers) { try { var serverInstance = server.Instance; if (serverInstance.Address != address) { serverInstance.Address = address; } serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout? return; } catch (Exception ex) { exceptions.Add(ex); } } var firstAddress = server.Settings.Servers.First(); var firstException = exceptions.First(); var message = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message); var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
internal void Connect( TimeSpan timeout ) { server.ClearInstances(); var exceptions = new List<Exception>(); foreach (var address in server.Settings.Servers) { try { var serverInstance = new MongoServerInstance(server, address); server.AddInstance(serverInstance); try { serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout? } catch { server.RemoveInstance(serverInstance); throw; } return; } catch (Exception ex) { exceptions.Add(ex); } } var innerException = exceptions.FirstOrDefault(); var connectionException = new MongoConnectionException("Unable to connect to server", innerException); if (exceptions.Count > 1) { connectionException.Data.Add("exceptions", exceptions); } throw connectionException; }
private static string MongoConnectionExceptionHandle(MongoConnectionException ex, List <TreeNode> trvMongoDb, TreeNode connectionNode, string mongoConnKey) { //暂时不处理任何异常,简单跳过 //无法连接的理由: //1.服务器没有启动 //2.认证模式不正确 if (!GuiConfig.IsUseDefaultLanguage) { connectionNode.Text += "[" + GuiConfig.GetText( TextType.ExceptionNotConnected) + "]"; Utility.ExceptionDeal(ex, GuiConfig.GetText(TextType.ExceptionNotConnected), GuiConfig.GetText(TextType.ExceptionNotConnectedNote)); } else { connectionNode.Text += "[Exception]"; Utility.ExceptionDeal(ex, "Not Connected", "Mongo Server may not Startup or Auth Mode is not correct"); } connectionNode.Tag = ConstMgr.ConnectionExceptionTag + ":" + mongoConnKey; trvMongoDb.Add(connectionNode); return(mongoConnKey); }
internal void Connect( TimeSpan timeout ) { server.ClearInstances(); var exceptions = new List <Exception>(); foreach (var address in server.Settings.Servers) { try { var serverInstance = new MongoServerInstance(server, address); server.AddInstance(serverInstance); try { serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout? } catch { server.RemoveInstance(serverInstance); throw; } return; } catch (Exception ex) { exceptions.Add(ex); } } var innerException = exceptions.FirstOrDefault(); var connectionException = new MongoConnectionException("Unable to connect to server.", innerException); if (exceptions.Count > 1) { connectionException.Data.Add("exceptions", exceptions); } throw connectionException; }
// internal methods internal void Connect(TimeSpan timeout) { var exceptions = new List <Exception>(); foreach (var address in server.Settings.Servers) { try { var serverInstance = server.Instance; if (serverInstance.Address != address) { serverInstance.Address = address; } serverInstance.Connect(server.Settings.SlaveOk); // TODO: what about timeout? return; } catch (Exception ex) { exceptions.Add(ex); } } var firstAddress = server.Settings.Servers.First(); var firstException = exceptions.First(); var message = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message); var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
internal void ShouldInvalidateServer_should_return_expected_result_for_exceptionType(string exceptionTypeName, bool expectedResult) { _subject.Initialize(); Exception exception; var clusterId = new ClusterId(1); var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017)); var connectionId = new ConnectionId(serverId); var command = new BsonDocument("command", 1); var commandResult = new BsonDocument("ok", 1); switch (exceptionTypeName) { case nameof(EndOfStreamException): exception = new EndOfStreamException(); break; case nameof(Exception): exception = new Exception(); break; case nameof(IOException): exception = new IOException(); break; case nameof(MongoConnectionException): exception = new MongoConnectionException(connectionId, "message"); break; case nameof(MongoNodeIsRecoveringException): exception = new MongoNodeIsRecoveringException(connectionId, command, commandResult); break; case nameof(MongoNotPrimaryException): exception = new MongoNotPrimaryException(connectionId, command, commandResult); break; case nameof(SocketException): exception = new SocketException(); break; default: throw new Exception($"Invalid exceptionTypeName: {exceptionTypeName}."); } var result = _subject.ShouldInvalidateServer(exception); result.Should().Be(expectedResult); }
public void Connect( TimeSpan timeout ) { var exceptions = new List <Exception>(); foreach (var endPoint in server.EndPoints) { try { Connect(endPoint, timeout); return; } catch (Exception ex) { exceptions.Add(ex); } } var innerException = exceptions.FirstOrDefault(); var connectionException = new MongoConnectionException("Unable to connect to server", innerException); if (exceptions.Count > 1) { connectionException.Data.Add("exceptions", exceptions); } throw connectionException; }
public void GetChannel_should_update_topology_and_clear_connection_pool_on_network_error_or_timeout( [Values("TimedOutSocketException", "NetworkUnreachableSocketException")] string errorType, [Values(false, true)] bool async) { var serverId = new ServerId(_clusterId, _endPoint); var connectionId = new ConnectionId(serverId); var innerMostException = CoreExceptionHelper.CreateException(errorType); var openConnectionException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException)); var mockConnection = new Mock <IConnectionHandle>(); mockConnection.Setup(c => c.Open(It.IsAny <CancellationToken>())).Throws(openConnectionException); mockConnection.Setup(c => c.OpenAsync(It.IsAny <CancellationToken>())).ThrowsAsync(openConnectionException); var connectionFactory = new Mock <IConnectionFactory>(); connectionFactory.Setup(cf => cf.CreateConnection(serverId, _endPoint)).Returns(mockConnection.Object); var mockExceptionHandler = new Mock <IConnectionExceptionHandler>(); var connectionPoolSettings = new ConnectionPoolSettings(); var connectionPool = new ExclusiveConnectionPool(serverId, _endPoint, connectionPoolSettings, connectionFactory.Object, new EventAggregator(), mockExceptionHandler.Object); var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>(); mockConnectionPoolFactory .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint, It.IsAny <IConnectionExceptionHandler>())) .Returns(connectionPool); var mockMonitorServerDescription = new ServerDescription(serverId, _endPoint); var mockServerMonitor = new Mock <IServerMonitor>(); mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerDescription); mockServerMonitor.SetupGet(m => m.Lock).Returns(new object()); var mockServerMonitorFactory = new Mock <IServerMonitorFactory>(); mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object); var subject = new DefaultServer(_clusterId, _clusterClock, _clusterConnectionMode, _connectionModeSwitch, _directConnection, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents, _serverApi); connectionPool._connectionExceptionHandler(subject); subject.Initialize(); connectionPool.SetReady(); IChannelHandle channel = null; Exception exception; if (async) { exception = Record.Exception(() => channel = subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult()); } else { exception = Record.Exception(() => channel = subject.GetChannel(CancellationToken.None)); } channel.Should().BeNull(); exception.Should().Be(openConnectionException); subject.Description.Type.Should().Be(ServerType.Unknown); subject.Description.ReasonChanged.Should().Contain("ChannelException during handshake"); }
public void GetChannel_should_not_update_topology_and_clear_connection_pool_on_MongoConnectionException( [Values("TimedOutSocketException", "NetworkUnreachableSocketException")] string errorType, [Values(false, true)] bool async) { var serverId = new ServerId(_clusterId, _endPoint); var connectionId = new ConnectionId(serverId); var innerMostException = CoreExceptionHelper.CreateException(errorType); var mockConnectionExceptionHandler = new Mock <IConnectionExceptionHandler>(); var openConnectionException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException)); var mockConnection = new Mock <IConnectionHandle>(); mockConnection.Setup(c => c.Open(It.IsAny <CancellationToken>())).Throws(openConnectionException); mockConnection.Setup(c => c.OpenAsync(It.IsAny <CancellationToken>())).ThrowsAsync(openConnectionException); var connectionFactory = new Mock <IConnectionFactory>(); connectionFactory.Setup(cf => cf.CreateConnection(serverId, _endPoint)).Returns(mockConnection.Object); var connectionPoolSettings = new ConnectionPoolSettings(); var connectionPool = new ExclusiveConnectionPool(serverId, _endPoint, connectionPoolSettings, connectionFactory.Object, new EventAggregator(), mockConnectionExceptionHandler.Object); var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>(); mockConnectionPoolFactory .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint, It.IsAny <IConnectionExceptionHandler>())) .Returns(connectionPool); var subject = new LoadBalancedServer(_clusterId, _clusterClock, _settings, _endPoint, mockConnectionPoolFactory.Object, _capturedEvents, _serverApi); subject.Initialize(); IChannelHandle channel = null; Exception exception; if (async) { exception = Record.Exception(() => channel = subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult()); } else { exception = Record.Exception(() => channel = subject.GetChannel(CancellationToken.None)); } channel.Should().BeNull(); exception.Should().Be(openConnectionException); subject.Description.Type.Should().Be(ServerType.LoadBalanced); subject.Description.ReasonChanged.Should().Be("Initialized"); subject.Description.State.Should().Be(ServerState.Connected); _mockConnectionPool.Verify(c => c.Clear(It.IsAny <bool>()), Times.Never); }
internal void Connect( TimeSpan timeout ) { timeoutAt = DateTime.UtcNow + timeout; // connect to all servers in the seed list in parallel (they will report responses back through the responseQueue) server.ClearInstances(); foreach (var address in server.Settings.Servers) { QueueConnect(address); } // process the responses as they come back and return as soon as we have connected to the primary // any remaining responses after the primary will be processed in the background while (responses.Count < connects.Count) { var timeRemaining = timeoutAt - DateTime.UtcNow; var response = responseQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } ProcessResponse(response); // return as soon as we've connected to the primary var serverInstance = response.ServerInstance; if (serverInstance.State == MongoServerState.Connected && serverInstance.IsPrimary) { // make sure this serverInstance is still an instance of this server // it might have been removed if the connection string used a DNS alias for the host // (in which case we have already queued a connect using the official host name and should see that response shortly) if (server.Instances.Contains(serverInstance)) { // process any additional responses in the background ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem); return; } } } var exceptions = responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray(); var innerException = exceptions.FirstOrDefault(); var exception = new MongoConnectionException("Unable to connect to server.", innerException); exception.Data.Add("InnerExceptions", exceptions); throw exception; }
/// <summary> /// Connects to the server respecting the timeout and readPreference. /// </summary> /// <param name="timeout">The timeout.</param> /// <param name="readPreference">The read preference.</param> public void Connect(TimeSpan timeout, ReadPreference readPreference) { if (_instance.State != MongoServerState.Connected) { lock (_stateLock) { if (_instance.State != MongoServerState.Connected) { _connectionAttempt++; var exceptions = new List <Exception>(); foreach (var address in _settings.Servers) { try { _instance.Address = address; _instance.Connect(); // TODO: what about timeout? if (_settings.ReplicaSetName != null && (_instance.InstanceType != MongoServerInstanceType.ReplicaSetMember || _instance.ReplicaSetInformation.Name != _settings.ReplicaSetName)) { exceptions.Add(new MongoConnectionException(string.Format("The server '{0}' is not a member of replica set '{1}'.", address, _settings.ReplicaSetName))); _instance.Disconnect(); continue; } if (_instance.IsMasterResult.MyAddress != null) { _instance.Address = _instance.IsMasterResult.MyAddress; } return; } catch (Exception ex) { exceptions.Add(ex); } } var firstAddress = _settings.Servers.First(); var firstException = exceptions.First(); var message = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message); var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; } } } }
internal void ShouldInvalidateServer_should_return_expected_result_for_exceptionType(string exceptionTypeName, bool expectedResult) { _subject.Initialize(); Exception exception; var clusterId = new ClusterId(1); var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017)); var connectionId = new ConnectionId(serverId); var command = new BsonDocument("command", 1); var notWritablePrimaryResult = new BsonDocument { { "code", ServerErrorCode.NotWritablePrimary } }; var nodeIsRecoveringResult = new BsonDocument("code", ServerErrorCode.InterruptedAtShutdown); switch (exceptionTypeName) { case nameof(EndOfStreamException): exception = new EndOfStreamException(); break; case nameof(Exception): exception = new Exception(); break; case nameof(IOException): exception = new IOException(); break; case nameof(MongoConnectionException): exception = new MongoConnectionException(connectionId, "message"); break; case nameof(MongoNodeIsRecoveringException): exception = new MongoNodeIsRecoveringException(connectionId, command, notWritablePrimaryResult); break; case nameof(MongoNotPrimaryException): exception = new MongoNotPrimaryException(connectionId, command, nodeIsRecoveringResult); break; case nameof(SocketException): exception = new SocketException(); break; case "MongoConnectionExceptionWithSocketTimeout": var innermostException = new SocketException((int)SocketError.TimedOut); var innerException = new IOException("Execute Order 66", innermostException); exception = new MongoConnectionException(connectionId, "Yes, Lord Sidious", innerException); break; case nameof(TimeoutException): exception = new TimeoutException(); break; case nameof(MongoExecutionTimeoutException): exception = new MongoExecutionTimeoutException(connectionId, "message"); break; default: throw new Exception($"Invalid exceptionTypeName: {exceptionTypeName}."); } var result = _subject.ShouldInvalidateServer(Mock.Of <IConnection>(), exception, new ServerDescription(_subject.ServerId, _subject.EndPoint), out _); result.Should().Be(expectedResult); }
public void Connect( TimeSpan timeout ) { var exceptions = new List<Exception>(); foreach (var endPoint in server.EndPoints) { try { Connect(endPoint, timeout); return; } catch (Exception ex) { exceptions.Add(ex); } } var innerException = exceptions.FirstOrDefault(); var connectionException = new MongoConnectionException("Unable to connect to server", innerException); if (exceptions.Count > 1) { connectionException.Data.Add("exceptions", exceptions); } throw connectionException; }
private void ThrowConnectionException(ReadPreference readPreference) { List <Exception> exceptions; lock (_lock) { exceptions = _instances.Select(x => x.ConnectException).Where(x => x != null).ToList(); } var firstException = exceptions.FirstOrDefault(); string message; if (firstException == null) { message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}", readPreference); } else { message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}: {1}.", readPreference, firstException.Message); } var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
// private methods private void EnrichExceptionDetails(MongoConnectionException ex) { // should be refactored in CSHARP-3720 ex.Generation = _generation; ex.ServiceId = _connection?.Description?.ServiceId; }
private void ThrowConnectionException(ReadPreference readPreference) { List<Exception> exceptions; lock (_lock) { exceptions = _instances.Select(x => x.ConnectException).Where(x => x != null).ToList(); } var firstException = exceptions.FirstOrDefault(); string message; if (firstException == null) { message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}", readPreference); } else { message = string.Format("Unable to connect to a member of the replica set matching the read preference {0}: {1}.", readPreference, firstException.Message); } var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
// internal methods internal void Connect(TimeSpan timeout, ConnectWaitFor waitFor) { _timeoutAt = DateTime.UtcNow + timeout; // connect to all server instances in parallel (they will report responses back through the responseQueue) // the set of Instances initially comes from the seed list, but is adjusted to the official set once connected foreach (var serverInstance in _server.Instances) { QueueConnect(serverInstance); } // process the responses as they come back and return as soon as we have connected to the primary // any remaining responses after the primary will be processed in the background while (_responses.Count < _connects.Count) { var timeRemaining = _timeoutAt - DateTime.UtcNow; var response = _responseQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } ProcessResponse(response); // return as soon as we can (according to the waitFor mode specified) bool exitEarly = false; switch (waitFor) { case ConnectWaitFor.All: if (_server.Instances.All(i => i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.AnySlaveOk: // don't check for IsPassive because IsSecondary is also true for passives (and only true if not in recovery mode) if (_server.Instances.Any(i => (i.IsPrimary || i.IsSecondary) && i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.Primary: var primary = _server.Primary; if (primary != null && primary.State == MongoServerState.Connected) { exitEarly = true; } break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } if (exitEarly) { if (_responses.Count < _connects.Count) { // process any additional responses in the background ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem); } return; } } string waitForString; switch (waitFor) { case ConnectWaitFor.All: waitForString = "all members"; break; case ConnectWaitFor.AnySlaveOk: waitForString = "any slaveOk member"; break; case ConnectWaitFor.Primary: waitForString = "the primary member"; break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } var exceptions = _responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray(); var firstException = exceptions.FirstOrDefault(); string message; if (firstException == null) { message = string.Format("Unable to connect to {0} of the replica set.", waitForString); } else { message = string.Format("Unable to connect to {0} of the replica set: {1}.", waitForString, firstException.Message); } var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
// internal methods internal void Connect(TimeSpan timeout, ConnectWaitFor waitFor) { _timeoutAt = DateTime.UtcNow + timeout; // connect to all server instances in parallel (they will report responses back through the responseQueue) // the set of Instances initially comes from the seed list, but is adjusted to the official set once connected foreach (var serverInstance in _server.Instances) { QueueConnect(serverInstance); } // process the responses as they come back and return as soon as we have connected to the primary // any remaining responses after the primary will be processed in the background while (_responses.Count < _connects.Count) { var timeRemaining = _timeoutAt - DateTime.UtcNow; var response = _responseQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } ProcessResponse(response); // return as soon as we can (according to the waitFor mode specified) bool exitEarly = false; switch (waitFor) { case ConnectWaitFor.All: if (_server.Instances.All(i => i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.AnySlaveOk: if (_server.Instances.Any(i => (i.IsPrimary || i.IsSecondary || i.IsPassive) && i.State == MongoServerState.Connected)) { exitEarly = true; } break; case ConnectWaitFor.Primary: var primary = _server.Primary; if (primary != null && primary.State == MongoServerState.Connected) { exitEarly = true; } break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } if (exitEarly) { if (_responses.Count < _connects.Count) { // process any additional responses in the background ThreadPool.QueueUserWorkItem(ProcessAdditionalResponsesWorkItem); } return; } } string waitForString; switch (waitFor) { case ConnectWaitFor.All: waitForString = "all members"; break; case ConnectWaitFor.AnySlaveOk: waitForString = "any slaveOk member"; break; case ConnectWaitFor.Primary: waitForString = "the primary member"; break; default: throw new ArgumentException("Invalid ConnectWaitFor value."); } var exceptions = _responses.Select(r => r.ServerInstance.ConnectException).Where(e => e != null).ToArray(); var firstException = exceptions.FirstOrDefault(); string message; if (firstException == null) { message = string.Format("Unable to connect to {0} of the replica set.", waitForString); } else { message = string.Format("Unable to connect to {0} of the replica set: {1}.", waitForString, firstException.Message); } var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; }
/// <summary> /// GetThreatLevel of MongoConnectionException /// </summary> /// <param name="exceptione"></param> /// <returns>Level</returns> public LogLevels.Levels GetThreatLevel(MongoConnectionException exceptione) { return(LogLevels.Levels.Error); }
public void HandleChannelException_should_update_topology_as_expected_on_network_error_or_timeout( string errorType, bool shouldUpdateTopology) { var serverId = new ServerId(_clusterId, _endPoint); var connectionId = new ConnectionId(serverId); Exception innerMostException; switch (errorType) { case "MongoConnectionExceptionWithSocketTimeout": innerMostException = new SocketException((int)SocketError.TimedOut); break; case nameof(MongoConnectionException): innerMostException = new SocketException((int)SocketError.NetworkUnreachable); break; default: throw new ArgumentException("Unknown error type."); } var operationUsingChannelException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException)); var mockConnection = new Mock <IConnectionHandle>(); var isMasterResult = new IsMasterResult(new BsonDocument { { "compressors", new BsonArray() } }); // the server version doesn't matter when we're not testing MongoNotPrimaryExceptions, but is needed when // Server calls ShouldClearConnectionPoolForException var buildInfoResult = new BuildInfoResult(new BsonDocument { { "version", "4.4.0" } }); mockConnection.SetupGet(c => c.Description) .Returns(new ConnectionDescription(new ConnectionId(serverId, 0), isMasterResult, buildInfoResult)); var mockConnectionPool = new Mock <IConnectionPool>(); mockConnectionPool.Setup(p => p.AcquireConnection(It.IsAny <CancellationToken>())).Returns(mockConnection.Object); mockConnectionPool.Setup(p => p.AcquireConnectionAsync(It.IsAny <CancellationToken>())).ReturnsAsync(mockConnection.Object); var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>(); mockConnectionPoolFactory .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint)) .Returns(mockConnectionPool.Object); var mockMonitorServerInitialDescription = new ServerDescription(serverId, _endPoint).With(reasonChanged: "Initial D", type: ServerType.Unknown); var mockServerMonitor = new Mock <IServerMonitor>(); mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerInitialDescription); mockServerMonitor.SetupGet(m => m.Lock).Returns(new object()); var mockServerMonitorFactory = new Mock <IServerMonitorFactory>(); mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object); var subject = new DefaultServer(_clusterId, _clusterClock, _clusterConnectionMode, _connectionModeSwitch, _directConnection, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents, _serverApi); subject.Initialize(); var heartbeatDescription = mockMonitorServerInitialDescription.With(reasonChanged: "Heartbeat", type: ServerType.Standalone); mockServerMonitor.Setup(m => m.Description).Returns(heartbeatDescription); mockServerMonitor.Raise( m => m.DescriptionChanged += null, new ServerDescriptionChangedEventArgs(mockMonitorServerInitialDescription, heartbeatDescription)); subject.Description.Should().Be(heartbeatDescription); subject.HandleChannelException(mockConnection.Object, operationUsingChannelException); if (shouldUpdateTopology) { subject.Description.Type.Should().Be(ServerType.Unknown); subject.Description.ReasonChanged.Should().Contain("ChannelException"); } else { subject.Description.Should().Be(heartbeatDescription); } }
/// <summary> /// Connects to the server respecting the timeout and readPreference. /// </summary> /// <param name="timeout">The timeout.</param> /// <param name="readPreference">The read preference.</param> public void Connect(TimeSpan timeout, ReadPreference readPreference) { if (_instance.State != MongoServerState.Connected) { lock (_stateLock) { if (_instance.State != MongoServerState.Connected) { _connectionAttempt++; var exceptions = new List<Exception>(); foreach (var address in _settings.Servers) { try { _instance.Address = address; _instance.Connect(); // TODO: what about timeout? if (_settings.ReplicaSetName != null && (_instance.InstanceType != MongoServerInstanceType.ReplicaSetMember || _instance.ReplicaSetInformation.Name != _settings.ReplicaSetName)) { exceptions.Add(new MongoConnectionException(string.Format("The server '{0}' is not a member of replica set '{1}'.", address, _settings.ReplicaSetName))); _instance.Disconnect(); continue; } if (_instance.IsMasterResult.MyAddress != null) { _instance.Address = _instance.IsMasterResult.MyAddress; } return; } catch (Exception ex) { exceptions.Add(ex); } } var firstAddress = _settings.Servers.First(); var firstException = exceptions.First(); var message = string.Format("Unable to connect to server {0}: {1}.", firstAddress, firstException.Message); var connectionException = new MongoConnectionException(message, firstException); connectionException.Data.Add("InnerExceptions", exceptions); // useful when there is more than one throw connectionException; } } } }
public void Connect( TimeSpan timeout ) { // query all servers in seed list in parallel (they will report responses back through the responsesQueue) var responsesQueue = QueueSeedListQueries(); // process the responses as they come back and stop as soon as we find the primary (unless SlaveOk is true) // stragglers will continue to report responses to the responsesQueue but no one will read them // and eventually it will all get garbage collected var exceptions = new List<Exception>(); var timeoutAt = DateTime.UtcNow + timeout; while (responses.Count < queries.Count) { var timeRemaining = timeoutAt - DateTime.UtcNow; var response = responsesQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } responses.Add(response.Address, response); if (response.Exception != null) { exceptions.Add(response.Exception); continue; } if (response.IsPrimary) { primaryConnection = response.Connection; replicaSet = GetHostAddresses(response); maxDocumentSize = response.MaxDocumentSize; maxMessageLength = response.MaxMessageLength; if (!server.Settings.SlaveOk) { break; // if we're not going to use the secondaries no need to wait for their replies } } else { if (server.Settings.SlaveOk) { secondaryConnections.Add(response.Connection); } else { response.Connection.Close(); } } // look for additional members of the replica set that might not have been in the seed list and query them also foreach (var address in GetHostAddresses(response)) { if (!queries.Contains(address)) { var args = new QueryNodeParameters { Address = address, EndPoint = address.ToIPEndPoint(server.Settings.AddressFamily), ResponseQueue = responsesQueue }; ThreadPool.QueueUserWorkItem(QueryNodeWorkItem, args); queries.Add(address); } } } if (primaryConnection == null) { var innerException = exceptions.FirstOrDefault(); var exception = new MongoConnectionException("Unable to connect to server", innerException); if (exceptions.Count > 1) { exception.Data.Add("InnerExceptions", exceptions); } throw exception; } }
private void ApplyApplicationError(BsonDocument applicationError) { var expectedKeys = new[] { "address", "generation", // optional "maxWireVersion", "when", "type", "response" // optional }; JsonDrivenHelper.EnsureAllFieldsAreValid(applicationError, expectedKeys); var address = applicationError["address"].AsString; var endPoint = EndPointHelper.Parse(address); var server = (Server)_serverFactory.GetServer(endPoint); var connectionId = new ConnectionId(server.ServerId); var type = applicationError["type"].AsString; var maxWireVersion = applicationError["maxWireVersion"].AsInt32; Exception simulatedException = null; switch (type) { case "command": var response = applicationError["response"].AsBsonDocument; var command = new BsonDocument("Link", "start!"); simulatedException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, command, response, "errmsg"); Ensure.IsNotNull(simulatedException, nameof(simulatedException)); break; case "network": { var innerException = CoreExceptionHelper.CreateException("IOExceptionWithNetworkUnreachableSocketException"); simulatedException = new MongoConnectionException(connectionId, "Ignorance, yet knowledge.", innerException); break; } case "timeout": { var innerException = CoreExceptionHelper.CreateException("IOExceptionWithTimedOutSocketException"); simulatedException = new MongoConnectionException(connectionId, "Chaos, yet harmony.", innerException); break; } default: throw new ArgumentException($"Unsupported value of {type} for type"); } var mockConnection = new Mock <IConnectionHandle>(); var isMasterResult = new IsMasterResult(new BsonDocument { { "compressors", new BsonArray() } }); var serverVersion = WireVersionHelper.MapWireVersionToServerVersion(maxWireVersion); var buildInfoResult = new BuildInfoResult(new BsonDocument { { "version", serverVersion } }); mockConnection.SetupGet(c => c.Description) .Returns(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult)); var generation = applicationError.Contains("generation") ? applicationError["generation"].AsInt32 : 0; mockConnection.SetupGet(c => c.Generation).Returns(generation); var when = applicationError["when"].AsString; switch (when) { case "beforeHandshakeCompletes": server.HandleBeforeHandshakeCompletesException(mockConnection.Object, simulatedException); break; case "afterHandshakeCompletes": server.HandleChannelException(mockConnection.Object, simulatedException); break; default: throw new ArgumentException($"Unsupported value of {when} for when."); } }
public void Connect( TimeSpan timeout ) { // query all servers in seed list in parallel (they will report responses back through the responsesQueue) var responsesQueue = QueueSeedListQueries(); // process the responses as they come back and stop as soon as we find the primary (unless SlaveOk is true) // stragglers will continue to report responses to the responsesQueue but no one will read them // and eventually it will all get garbage collected var exceptions = new List <Exception>(); var timeoutAt = DateTime.UtcNow + timeout; while (responses.Count < queries.Count) { var timeRemaining = timeoutAt - DateTime.UtcNow; var response = responsesQueue.Dequeue(timeRemaining); if (response == null) { break; // we timed out } responses.Add(response.Address, response); if (response.Exception != null) { exceptions.Add(response.Exception); continue; } if (response.IsPrimary) { primaryConnection = response.Connection; replicaSet = GetHostAddresses(response); maxDocumentSize = response.MaxDocumentSize; maxMessageLength = response.MaxMessageLength; if (!server.Settings.SlaveOk) { break; // if we're not going to use the secondaries no need to wait for their replies } } else { if (server.Settings.SlaveOk) { secondaryConnections.Add(response.Connection); } else { response.Connection.Close(); } } // look for additional members of the replica set that might not have been in the seed list and query them also foreach (var address in GetHostAddresses(response)) { if (!queries.Contains(address)) { var args = new QueryNodeParameters { Address = address, EndPoint = address.ToIPEndPoint(server.Settings.AddressFamily), ResponseQueue = responsesQueue }; ThreadPool.QueueUserWorkItem(QueryNodeWorkItem, args); queries.Add(address); } } } if (primaryConnection == null) { var innerException = exceptions.FirstOrDefault(); var exception = new MongoConnectionException("Unable to connect to server", innerException); if (exceptions.Count > 1) { exception.Data.Add("InnerExceptions", exceptions); } throw exception; } }
public void GetChannel_should_update_topology_and_clear_connection_pool_on_network_error_or_timeout( [Values("timedout", "networkunreachable")] string errorType, [Values(false, true)] bool async) { var serverId = new ServerId(_clusterId, _endPoint); var connectionId = new ConnectionId(serverId); var innerMostException = CoreExceptionHelper.CreateSocketException(errorType); var openConnectionException = new MongoConnectionException(connectionId, "Oops", new IOException("Cry", innerMostException)); var mockConnection = new Mock <IConnectionHandle>(); mockConnection.Setup(c => c.Open(It.IsAny <CancellationToken>())).Throws(openConnectionException); mockConnection.Setup(c => c.OpenAsync(It.IsAny <CancellationToken>())).ThrowsAsync(openConnectionException); var mockConnectionPool = new Mock <IConnectionPool>(); mockConnectionPool.Setup(p => p.AcquireConnection(It.IsAny <CancellationToken>())).Returns(mockConnection.Object); mockConnectionPool.Setup(p => p.AcquireConnectionAsync(It.IsAny <CancellationToken>())).ReturnsAsync(mockConnection.Object); var mockConnectionPoolFactory = new Mock <IConnectionPoolFactory>(); mockConnectionPoolFactory .Setup(f => f.CreateConnectionPool(It.IsAny <ServerId>(), _endPoint)) .Returns(mockConnectionPool.Object); var mockMonitorServerDescription = new ServerDescription(serverId, _endPoint); var mockServerMonitor = new Mock <IServerMonitor>(); mockServerMonitor.SetupGet(m => m.Description).Returns(mockMonitorServerDescription); mockServerMonitor .Setup(m => m.Invalidate(It.IsAny <string>())) .Callback((string reason) => MockMonitorInvalidate(reason)); var mockServerMonitorFactory = new Mock <IServerMonitorFactory>(); mockServerMonitorFactory.Setup(f => f.Create(It.IsAny <ServerId>(), _endPoint)).Returns(mockServerMonitor.Object); var subject = new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, _endPoint, mockConnectionPoolFactory.Object, mockServerMonitorFactory.Object, _capturedEvents); subject.Initialize(); IChannelHandle channel = null; Exception exception; if (async) { exception = Record.Exception(() => channel = subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult()); } else { exception = Record.Exception(() => channel = subject.GetChannel(CancellationToken.None)); } channel.Should().BeNull(); exception.Should().Be(openConnectionException); subject.Description.Type.Should().Be(ServerType.Unknown); subject.Description.ReasonChanged.Should().Contain("ChannelException during handshake"); mockServerMonitor.Verify(m => m.Invalidate(It.IsAny <string>()), Times.Once); mockConnectionPool.Verify(p => p.Clear(), Times.Once); void MockMonitorInvalidate(string reason) { var currentDescription = mockServerMonitor.Object.Description; mockServerMonitor.SetupGet(m => m.Description).Returns(currentDescription.With(reason)); } }