/// <summary> /// Run the test (send and receive messages) with sessions abort activity. /// </summary> /// <param name="delay"></param> public void RunTest(int delay) { LogHelper.Log("SessionId: {0}; Entering RunTest", this.SessionId); Assert.IsNotNull(this.InboundSession, "Null inbound session in RunTest for SessionId#{0}", this.SessionId); Assert.IsNotNull(this.OutboundSession, "Null outbound session in RunTest for SessionId#{0}", this.SessionId); Thread.Sleep(delay); Random myRandGen = new Random(unchecked ((int)DateTime.Now.Ticks)); DateTime start = DateTime.Now; LogHelper.Log("SessionId: {0}; Started; MessageCount: {1}", this.SessionId, this.messageCount); // Send Action Delegate - Prepare and send the messages Action sendAction = (() => this.SendAndRecordMessages(myRandGen)); // Receive Action Delegate - receive and record the messages Action receiveAction = (() => this.ReceiveAndRecordMessages()); // Start the send and receive actions Task sendTask = Task.Factory.StartNew(sendAction); Task receiveTask = Task.Factory.StartNew(receiveAction); // While the tests are running, randomly abort the sessions. bool abortOccurred = this.RunRandomSessionAbortTest(myRandGen); // Wait for the send and receive tasks to complete bool sendCompleted = sendTask.Wait(Int32.MaxValue); bool receiveCompleted = receiveTask.Wait(Int32.MaxValue); Assert.IsTrue(sendCompleted, "sendCOmpleted false in RunTest for SessionId: {0} MessageCount: {1} Aborted: {2}", this.SnapshotOutbound.SessionId, this.messageCount, abortOccurred); Assert.IsTrue(receiveCompleted, "receiveCompleted false in RunTest for SessionId: {0} MessageCount: {1} Aborted: {2}", this.SnapshotInbound.SessionId, this.messageCount, abortOccurred); this.SnapshotInbound = this.InboundSession.GetDataSnapshot(); this.SnapshotOutbound = this.OutboundSession.GetDataSnapshot(); DateTime finish = DateTime.Now; if (!abortOccurred) { Assert.AreEqual(this.totalBytesSent, this.totalBytesReceived, "totalBytesSent != totalBytesReceived in RunTest for SessionId#{0}", this.SessionId); for (int i = 0; i < this.messageCount; i++) { Assert.IsNotNull(this.flatMessagesSent[i], "flatMessagesSent[{0}] is NULL in RunTest for SessionId#{1}", i, this.SessionId); Assert.IsNotNull(this.flatMessagesReceived[i], "flatMessagesReceived[{0}] is NULL in RunTest for SessionId#{1}", i, this.SessionId); // message content is the same: sent and received bool checkContent = Enumerable.SequenceEqual(this.flatMessagesReceived[i], this.flatMessagesSent[i]); //message structure is the same: sent and received int[] sentSizes = this.actualMessagesSent[i].Select(elem => elem.Length).ToArray(); int[] receivedSizes = this.actualMessagesReceived[i].Select(elem => elem.Length).ToArray(); bool checkStructure = Enumerable.SequenceEqual(sentSizes, receivedSizes); Assert.IsTrue(checkContent, "flatMessagesReceived[{0}] != flatMessagesSent[{0}] in RunTest for SessionId#{1}", i, this.SessionId); Assert.IsTrue(checkStructure, "receivedSizes[{0}] != sentSizes[{0}] in RunTest for SessionId#{1}", i, this.SessionId); } LogHelper.Log("SessionId: {0}; Completed; MessageCount: {1}; Avg Size: {2}; Duration {3} MilliSeconds", this.SessionId, this.messageCount, this.totalBytesSent / this.messageCount, (finish.Ticks - start.Ticks) / TimeSpan.TicksPerMillisecond); } else { LogHelper.Log("SessionId: {0}; Aborted; MessageCount: {1}; Avg Size: {2}; Duration {3} MilliSeconds", this.SessionId, this.messageCount, this.totalBytesSent / this.messageCount, (finish.Ticks - start.Ticks) / TimeSpan.TicksPerMillisecond); } LogHelper.Log("SessionId: {0}; Exiting RunTest", this.SessionId); }
/// <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); }