/// <summary> /// Executes the AMQP network detach operation. /// </summary> /// <param name="timeout"> /// Timeout to wait for for detach response. A timeout of 0 or less will not block to wait for a response. /// </param> /// <param name="cause">Error to detach link. Can be null.</param> /// <exception cref="Amqp.AmqpException"> /// Throws when an error occur during amqp detach. Or contains Error response from detach. /// </exception> /// <exception cref="System.TimeoutException"> /// Throws when detach response is not received in specified timeout. /// </exception> protected override void DoClose(TimeSpan timeout, Error cause = null) { if (IsDurable) { Task t = this.Link.DetachAsync(cause); if (TimeSpan.Compare(timeout, TimeSpan.Zero) > 0) { /* * AmqpNetLite does not allow a timeout to be specific for link detach request even though * it uses the same close operation which takes a parameter for timeout. AmqpNetLite uses * it default timeout of 60000ms, see AmqpObject.DefaultTimeout, for the detach close * operation forcing the detach request to be synchronous. To allow for asynchronous detach * request an NMS MessageConsumer must call the DetachAsync method on a link which will block * for up to 60000ms asynchronously to set a timeout exception or complete the task. */ const int amqpNetLiteDefaultTimeoutMillis = 60000; // taken from AmqpObject.DefaultTimeout TimeSpan amqpNetLiteDefaultTimeout = TimeSpan.FromMilliseconds(amqpNetLiteDefaultTimeoutMillis); // Create timeout which allows for the 60000ms block in the DetachAsync task. TimeSpan actualTimeout = amqpNetLiteDefaultTimeout + timeout; TaskUtil.Wait(t, actualTimeout); if (t.Exception != null) { if (t.Exception is AggregateException) { throw t.Exception.InnerException; } else { throw t.Exception; } } } } else { base.DoClose(timeout, cause); } }
internal void Connect() { if (this.state.CompareAndSet(ConnectionState.INITIAL, ConnectionState.CONNECTING)) { Address addr = UriUtil.ToAddress(connInfo.remoteHost, connInfo.username, connInfo.password ?? string.Empty); Tracer.InfoFormat("Creating Address: {0}", addr.Host); if (this.clientIdCanSet.CompareAndSet(true, false)) { if (this.ClientId == null) { connInfo.ResourceId = this.clientIdGenerator.GenerateId(); } else { connInfo.ResourceId = new Id(ClientId); } Tracer.InfoFormat("Staring Connection with Client Id : {0}", this.ClientId); } Open openFrame = CreateOpenFrame(this.connInfo); Task <Amqp.Connection> fconn = this.implCreate(addr, openFrame, this.OpenResponse); // wait until the Open request is sent this.impl = TaskUtil.Wait(fconn, connInfo.connectTimeout); if (fconn.Exception != null) { // exceptions thrown from TaskUtil are typically System.AggregateException and are usually transport exceptions for secure transport. // extract the innerException of interest and wrap it as an NMS exception if (fconn.Exception is AggregateException) { throw ExceptionSupport.Wrap(fconn.Exception.InnerException, "Failed to connect host {0}. Cause: {1}", openFrame.HostName, fconn.Exception.InnerException?.Message ?? fconn.Exception.Message); } else { throw ExceptionSupport.Wrap(fconn.Exception, "Failed to connect host {0}. Cause: {1}", openFrame.HostName, fconn.Exception?.Message); } } this.impl.Closed += OnInternalClosed; this.impl.AddClosedCallback(OnInternalClosed); this.latch = new CountDownLatch(1); ConnectionState finishedState = ConnectionState.UNKNOWN; // Wait for Open response try { bool received = this.latch.await((this.Info.requestTimeout == 0) ? Timeout.InfiniteTimeSpan : this.RequestTimeout); if (received && this.impl.Error == null && fconn.Exception == null) { Tracer.InfoFormat("Connection {0} has connected.", this.impl.ToString()); finishedState = ConnectionState.CONNECTED; // register connection factory once client Id accepted. MessageFactory <ConnectionInfo> .Register(this); } else { if (!received) { // Timeout occured waiting on response Tracer.InfoFormat("Connection Response Timeout. Failed to receive response from {0} in {1}ms", addr.Host, this.Info.requestTimeout); } finishedState = ConnectionState.INITIAL; if (fconn.Exception == null) { if (!received) { throw ExceptionSupport.GetTimeoutException(this.impl, "Connection {0} has failed to connect in {1}ms.", ClientId, connInfo.closeTimeout); } Tracer.ErrorFormat("Connection {0} has Failed to connect. Message: {1}", ClientId, (this.impl.Error == null ? "Unknown" : this.impl.Error.ToString())); throw ExceptionSupport.GetException(this.impl, "Connection {0} has failed to connect.", ClientId); } else { throw ExceptionSupport.Wrap(fconn.Exception, "Connection {0} failed to connect.", ClientId); } } } finally { this.latch = null; this.state.GetAndSet(finishedState); if (finishedState != ConnectionState.CONNECTED) { this.impl.Close(TimeSpan.FromMilliseconds(connInfo.closeTimeout), null); } } } }