/// <summary> /// Abort the given session. /// </summary> /// <param name="session">Session to Abort</param> /// <returns>true if session aborted, false otherwise</returns> bool AbortSession(IReliableMessagingSession session) { bool abortOccurred = true; try { LogHelper.Log("SessionId: {0}; Entering AbortSession", this.SessionId); session.Abort(); } catch (Exception e) { // this may occur because either the session closed before abort or because the abort at the // opposite end caused a message driven abort before the API could be invoked Assert.AreEqual(e.GetType(), typeof(InvalidOperationException), "Unexpected exception in AbortSession"); abortOccurred = false; } LogHelper.Log("SessionId: {0}; Exiting AbortSession", this.SessionId); return(abortOccurred); }
/// <summary> /// When the OutBoundSessionDriver is disposed, Abort and clear the corresponding outbound session. /// </summary> /// <param name="targetPartition">Clear the Reliable MessagingSession for the target Partition</param> internal void ClearOutboundSession(PartitionKey targetPartition) { FabricEvents.Events.ClearOutboundSession("Start@" + this.streamManager.TraceType, targetPartition.ToString(), ""); IReliableMessagingSession outboundSession = null; var normalizedPartition = this.GetNormalizedPartitionKey(targetPartition); var found = this.activeOutboundSessions.TryRemove(normalizedPartition, out outboundSession); if (found) { var snapshot = outboundSession.GetDataSnapshot(); outboundSession.Abort(); FabricEvents.Events.ClearOutboundSession( "Aborted@" + this.streamManager.TraceType, normalizedPartition.ToString(), snapshot.SessionId.ToString()); } else { FabricEvents.Events.ClearOutboundSession("NotFound@" + this.streamManager.TraceType, normalizedPartition.ToString(), ""); } }
/// <summary> /// Instantiates a Reliable Messaging Session for a given target partition. /// </summary> /// <param name="targetPartition">Target Partition</param> /// <param name="timeout">Timeout for the operation to complete</param> /// <returns>Reliable Messaging Session for the Target Partition</returns> internal async Task <IReliableMessagingSession> SetupSession(PartitionKey targetPartition, TimeSpan timeout) { string endpoint = null; var setupSuccess = false; IReliableMessagingSession session = null; var baseOpenAsyncTimeout = 0; var remainingTimeout = timeout; SessionDataSnapshot snapshot = null; try { while (!setupSuccess) { var beforeGetEndpoint = DateTime.UtcNow; // Get End point for this Partition var partitionInfo = await this.GetEndpointAsync(targetPartition, remainingTimeout); endpoint = partitionInfo.EndPoint; FabricEvents.Events.SetupSession("Start@" + this.streamManager.TraceType, targetPartition.ToString(), endpoint, Guid.Empty.ToString()); var afterGetEndpoint = DateTime.UtcNow; remainingTimeout = TimeoutHandler.UpdateTimeout(remainingTimeout, beforeGetEndpoint, afterGetEndpoint); session = await this.CreateSession(targetPartition, endpoint); var retry = false; snapshot = session.GetDataSnapshot(); FabricEvents.Events.SetupSession( "OpenSession.Start@" + this.streamManager.TraceType, targetPartition.ToString(), endpoint, snapshot.SessionId.ToString()); var openTask = session.OpenAsync(CancellationToken.None); var beforeOpenWait = DateTime.UtcNow; baseOpenAsyncTimeout = baseOpenAsyncTimeout >= StreamConstants.MaxDelayForValidSessionEndpoint ? StreamConstants.MaxDelayForValidSessionEndpoint : baseOpenAsyncTimeout + StreamConstants.BaseDelayForValidSessionEndpoint; var baseTimeSpan = new TimeSpan(0, 0, 0, 0, baseOpenAsyncTimeout); var openAsyncTimeout = (baseTimeSpan < remainingTimeout) || (remainingTimeout == Timeout.InfiniteTimeSpan) ? baseTimeSpan : remainingTimeout; // this timeout is a retry mechanism in case we are going to the wrong endpoint because the primary replica is moving var openTaskCompleted = await TimeoutHandler.WaitWithDelay(openAsyncTimeout, openTask); var afterOpenWait = DateTime.UtcNow; remainingTimeout = TimeoutHandler.UpdateTimeout(remainingTimeout, beforeOpenWait, afterOpenWait); if (openTaskCompleted && openTask.Exception == null) { FabricEvents.Events.SetupSession( "OpenSession.Finish@" + this.streamManager.TraceType, targetPartition.ToString(), endpoint, snapshot.SessionId.ToString()); setupSuccess = true; } else if (openTask.Exception != null) { if (openTask.Exception.InnerException.GetType() == typeof(FabricException)) { var fabricException = openTask.Exception.InnerException as FabricException; if (fabricException.ErrorCode == FabricErrorCode.ReliableSessionManagerNotFound) { // Target partition primary may be moving to a different host process before session manager was created retry = true; } } else { Tracing.WriteExceptionAsError( "SetupSession.OpenSession.UnrecoverableError", openTask.Exception, "{0} Target: {1}", this.tracer, targetPartition); throw openTask.Exception; } } else { FabricEvents.Events.SetupSession( "OpenSession.RetryTimeout@" + this.streamManager.TraceType, targetPartition.ToString(), endpoint, snapshot.SessionId.ToString()); retry = true; } if (retry) { session.Abort(); session = null; setupSuccess = false; } else { // control should never come here if we did not succeed; we should have thrown any non-retriable exception or set retry=true for a retriable exception Diagnostics.Assert(setupSuccess, "SetupSession.CodingError {0} Target: {1}", this.tracer, targetPartition); } } } catch (TimeoutException) { if (session != null) { // Abort the session and leave a clean slate for the next time we try to set up the session: we don't want a ReliableSessionAlreadyExists exception session.Abort(); session = null; } throw; } catch (FabricObjectClosedException) { // this can happen if the session manager was closed by a parallel thread due to role change var endpointString = endpoint ?? "NullEndpoint"; var sessionIdString = snapshot == null ? "NoSessionCreated" : snapshot.SessionId.ToString(); FabricEvents.Events.SetupSession( "ObjectClosed@" + this.streamManager.TraceType, targetPartition.ToString(), endpointString, sessionIdString); throw; } catch (Exception e) { Tracing.WriteExceptionAsError("SetupSession.Failure", e, "Source: {0} Target: {1}", this.tracer, targetPartition); Diagnostics.Assert( false, "{0} Unexpected exception {1} in SessionConnectionManager.SetupSession for Target: {2}", this.tracer, e.GetType(), targetPartition); } Diagnostics.Assert( session != null, "{0} SessionConnectionManager.SetupSession returning null session for Target: {1}", this.tracer, targetPartition); if (session != null) { snapshot = session.GetDataSnapshot(); Diagnostics.Assert( snapshot.IsOpenForSend, "SessionConnectionManager.SetupSession returning session that is not open for send for Source: {0} Target: {1}", this.tracer, targetPartition); FabricEvents.Events.SetupSession( "Finish@" + this.streamManager.TraceType, targetPartition.ToString(), endpoint, snapshot.SessionId.ToString()); } return(session); }