public void PutRequestTest() { var f = new MockBrokerQueueFactory(); var ob = new MockBrokerObserver(); var adapter = new RequestQueueAdapter(ob, f); var item = new BrokerQueueItem(SampleMessage, Guid.NewGuid(), null); DispatchData data = new DispatchData("1", 1, "1") { BrokerQueueItem = item, MessageId = Guid.NewGuid() }; adapter.PutRequestBack(data); Assert.AreEqual(1, ob.RequestProcessingCompletedInvokedTimes, "RequestProcessingCompleted of BrokerObserver should be invoked once."); Assert.IsNull(data.BrokerQueueItem, "BrokerQueueItem property should be set to null after put back."); Assert.AreEqual(1, f.PutResponseAsyncInvokedTimes, "PutResponseAsync should be invoked once."); var messageList = f.PutMessageDic.ToList(); Assert.AreEqual(1, messageList.Count, "There should be only one message put."); Assert.AreEqual(item, messageList[0].Key, "BrokerQueueItem should match."); Assert.AreEqual(1, messageList[0].Value.Count, "There should be only one response for the request queue item."); Assert.AreEqual(null, messageList[0].Value[0], "Response message should be null."); }
/// <summary> /// Get a response from the storage /// </summary> /// <param name="callback">the response callback, the async result should be the BrokerQueueItem</param> /// <param name="callbackState">the state object for the callback</param> public void GetResponseAsync(PersistCallback callback, object callbackState) { if (this.isClosedField) { BrokerTracing.TraceWarning("[MemoryPersist] .GetResponseAsync: the queue is closed."); return; } BrokerQueueItem responseItem = null; try { lock (this.lockResponseQueueField) { responseItem = this.responseQueueField.Dequeue(); } } catch (InvalidOperationException) { BrokerTracing.TraceError("[MemoryPersist] .GetResponseAsync: no response available. sessionId = {0}, clientId = {1}", this.sessionIdField, this.clientIdField); } if (callback == null) { return; } ThreadPool.QueueUserWorkItem(this.GetOperationComplete, new GetCallbackContext(callback, callbackState, responseItem)); }
public void PutResponseBackDummyExceptionTest() { var f = new MockBrokerQueueFactory(); var ob = new MockBrokerObserver(); var sampleMessage = Message.CreateMessage(MessageVersion.Default, "SampleAction"); sampleMessage.Headers.MessageId = new UniqueId(Guid.NewGuid()); var adapter = new ResponseQueueAdapter(ob, f, 4); var item = new BrokerQueueItem(DummyRequestContext.GetInstance(MessageVersion.Soap11), sampleMessage, Guid.NewGuid(), null); DispatchData data = new DispatchData("1", 1, "1") { BrokerQueueItem = item, MessageId = Guid.NewGuid(), DispatchTime = new DateTime(2000, 1, 1), Exception = new FaultException <RetryOperationError>(new RetryOperationError("Reason")), }; adapter.PutResponseBack(data); Assert.IsTrue(ob.Duration > 0, "The call duration should be greater than 0"); Assert.AreEqual(f.PutMessageDic.Count, 1, "There must be 1 and only 1 instance"); Assert.AreEqual(f.PutResponseAsyncInvokedTimes, 1, "There must be 1 and only 1 invoke"); Assert.AreSame(f.PutMessageDic.First().Key, item, "The put back BrokerQueueItem should be the same as the original one."); Assert.AreEqual(f.PutMessageDic.First().Value.Count, 1, "The response message should only be one."); Assert.AreSame(f.PutMessageDic.First().Value[0].Headers.RelatesTo, item.Message.Headers.MessageId, "The put back Message should be the same as the original one."); Assert.IsNull(data.BrokerQueueItem, "BrokerQueueItem property should be set to null after put back."); Assert.IsNull(data.ReplyMessage, "The reply message should be null after put back."); Assert.IsNull(data.Exception, "The Exception should be null after put back."); }
public void PutResponseBackPassTest() { var f = new MockBrokerQueueFactory(); var ob = new MockBrokerObserver(); var sampleMessage = Message.CreateMessage(MessageVersion.Default, "SampleAction"); sampleMessage.Headers.MessageId = new UniqueId(Guid.NewGuid()); var mockDuplexRequestContext = new MockDuplexRequestContext(sampleMessage); var adapter = new ResponseQueueAdapter(ob, f, 4); var item = new BrokerQueueItem(mockDuplexRequestContext, sampleMessage, Guid.NewGuid(), null); var message = Message.CreateMessage(MessageVersion.Default, "Default"); DispatchData data = new DispatchData("1", 1, "1") { BrokerQueueItem = item, MessageId = Guid.NewGuid(), DispatchTime = new DateTime(2000, 1, 1), ReplyMessage = message, }; adapter.PutResponseBack(data); Assert.IsTrue(ob.Duration > 0, "The call duration should be greater than 0"); Assert.AreSame(mockDuplexRequestContext.ReplyMessage, message, "The put back Message should be the same as the original one."); Assert.IsNull(data.BrokerQueueItem, "BrokerQueueItem property should be set to null after put back."); Assert.IsNull(data.ReplyMessage, "The reply message should be null after put back."); Assert.IsNull(data.Exception, "The Exception should be null after put back."); }
/// <summary> /// BrokerQueueCallback root method /// </summary> /// <param name="item">indicating the broker queue item</param> /// <param name="state">indicating the state</param> public void CallbackRoot(BrokerQueueItem item, object state) { if (!this.refObj.IncreaseCount()) { throw new ObjectDisposedException("dispatcher"); } try { this.brokerQueueCallback(item, state); } finally { try { this.refObj.DecreaseCount(); } catch (ThreadAbortException) { } catch (AppDomainUnloadedException) { } catch (Exception e) { BrokerTracing.TraceEvent(TraceEventType.Critical, 0, "[ReferencedThreadHelper] Exception catched while disposing the object: {0}", e); } } }
public void PutResponseAsync(Message responseMsg, BrokerQueueItem requestItem) { Interlocked.Increment(ref this.putResponseAsyncInvokedTimes); this.messageDic.AddOrUpdate( requestItem, x => new List <Message>() { responseMsg }, (x, list) => { list.Add(responseMsg); return(list); }); }
/// <summary> /// Put a single request item into the storage. /// </summary> /// <param name="request">the single request that need be stored to the persistenc</param> /// <param name="putRequestCallback">the callback function that will be called once the async operation finish or exception raise.</param> /// <param name="callbackState">the state object for the callback.</param> public async Task PutRequestAsync(BrokerQueueItem request, PutRequestCallback putRequestCallback, object callbackState) { if (this.isClosedField) { BrokerTracing.TraceWarning("[MemoryPersist] .GetRequestAsync: the queue is closed."); return; } request.PersistAsyncToken.AsyncToken = this.PersistToken; this.requestQueueField.Enqueue(request); Interlocked.Increment(ref this.allRequestCountField); Interlocked.Increment(ref this.requestCountField); PutRequestComplete(putRequestCallback, callbackState); }
public async Task GetRequestTest() { var request = new BrokerQueueItem( null, Message.CreateMessage(MessageVersion.Soap12WSAddressing10, action, shortMsg), null); await this.sessionPersist.PutRequestAsync(request, null, 0); this.sessionPersist.GetRequestAsync(this.GetMessageTestCallback, null); while (!this.CallbackIsCalled) { await Task.Delay(millisecondsDelay); } Assert.AreEqual(true, this.IsExpected); }
/// <summary> /// acknowledge that a response message is dispatched, either successfully or not /// </summary> /// <param name="responseItem">response message being dispatched</param> /// <param name="success">if dispatching is success or not</param> public void AckResponse(BrokerQueueItem responseMessage, bool success) { if (success) { responseMessage.Dispose(); return; } // if failed to send response, response message is put back responseMessage.PrepareMessage(); // put response back lock (this.lockResponseQueueField) { this.filteredOutResponseQueueField.Enqueue(responseMessage); } }
public async Task GetLargeResponseTest() { var response = new BrokerQueueItem( null, Message.CreateMessage(MessageVersion.Soap12WSAddressing10, action, largeMsg), null); response.PersistAsyncToken.AsyncToken = Guid.NewGuid().ToString(); response.PeerItem = new BrokerQueueItem( null, Message.CreateMessage(MessageVersion.Soap12WSAddressing10, action, largeMsg), null); this.sessionPersist.PutResponseAsync(response, null, 0); this.sessionPersist.GetResponseAsync(this.GetLargeMessageTestCallback, null); while (!this.CallbackIsCalled) { await Task.Delay(millisecondsDelay); } Assert.AreEqual(true, this.IsExpected); }
/// <summary> /// Put on response item into persistence /// </summary> /// <param name="response">the response item to be persisted</param> /// <param name="putResponseCallback">the callback function that will be called once the async operation finish or exception raise.</param> /// <param name="callbackState">the state object for the callback.</param> public void PutResponseAsync(BrokerQueueItem response, PutResponseCallback putResponseCallback, object callbackState) { bool isFaultResponse = response.Message.IsFault; lock (this.lockResponseQueueField) { this.responseQueueField.Enqueue(response); Interlocked.Increment(ref this.responseCountField); } response.PeerItem.Dispose(); response.PeerItem = null; if (isFaultResponse) { Interlocked.Increment(ref this.failedRequestCountField); } bool isLastResponse = (Interlocked.Decrement(ref this.requestCountField) == 0); PutResponseComplete(1, isFaultResponse ? 1 : 0, isLastResponse, putResponseCallback, callbackState); }
/// <summary> /// Fetch the requests one by one from the storage but not remove the original message in the storage. /// </summary> /// <param name="callback">the callback to get the async result</param> /// <param name="state">the state object for the callback</param> public void GetRequestAsync(PersistCallback callback, object state) { if (this.isClosedField) { BrokerTracing.TraceWarning("[MemoryPersist] .GetRequestAsync: the queue is closed."); return; } BrokerQueueItem requestItem = null; if (!this.requestQueueField.TryDequeue(out requestItem)) { BrokerTracing.TraceError("[MemoryPersist] .GetRequestAsync: no request available. sessionId={0}, clientId={1}", this.sessionIdField, this.clientIdField); } if (callback == null) { return; } ThreadPool.QueueUserWorkItem(this.GetOperationComplete, new GetCallbackContext(callback, state, requestItem)); }
public void HandleEndpointNotFoundException(int clientIndex, BackEnd.IService client, BrokerQueueItem item, Guid messageId, System.ServiceModel.EndpointNotFoundException e) { }
public void HandleStorageException(DateTime dispatchTime, int clientIndex, BackEnd.IService client, BrokerQueueItem item, Guid messageId, StorageException e) { }
public Task HandleException(DateTime dispatchTime, int clientIndex, BackEnd.IService client, BrokerQueueItem item, Guid messageId, Exception e) { return(Task.CompletedTask); }
public bool HandleFaultExceptionRetry(int clientIndex, BrokerQueueItem item, Message reply, DateTime dispatchTime, out bool preemption) { preemption = false; return(true); }
private void GetLargeMessageTestCallback(BrokerQueueItem persistMessage, object state, Exception exception) { this.IsExpected = persistMessage.Message.GetBody <byte[]>().SequenceEqual(largeMsg); this.CallbackIsCalled = true; }
/// <summary> /// Receive response message /// </summary> /// <param name="item">broker queue item</param> /// <param name="asyncState">async state</param> private void ReceiveResponse(BrokerQueueItem item, object asyncState) { if (this.callbackChannelDisposed) { throw new Exception("Callback channel was disposed"); } this.ResetTimeout(); BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Verbose, 0, "[BrokerClient] Client {0}: Receive Response from BrokerQueue", this.clientId); object[] objArray = asyncState as object[]; IResponseServiceCallback callback = (IResponseServiceCallback)objArray[0]; string clientData = objArray[1].ToString(); Message response = this.ConvertMessage(item.Message); int index = response.Headers.FindHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS); if (index < 0) { response.Headers.Add(MessageHeader.CreateHeader(Constant.ResponseCallbackIdHeaderName, Constant.ResponseCallbackIdHeaderNS, clientData)); } Exception exception = null; try { if (callback is AzureQueueProxy) { callback.SendResponse(response, clientData); } else { callback.SendResponse(response); } BrokerTracing.EtwTrace.LogFrontEndResponseSent(this.SharedData.BrokerInfo.SessionId, this.clientId, Utility.GetMessageIdFromResponse(response)); this.IncreaseResponsesCount(); } catch (ObjectDisposedException e) { this.callbackChannelDisposed = true; exception = new Exception("Callback channel is disposed", e); throw exception; } catch (CommunicationObjectFaultedException e) { this.callbackChannelDisposed = true; exception = new Exception("Callback channel is faulted", e); throw exception; } catch (CommunicationObjectAbortedException e) { this.callbackChannelDisposed = true; exception = new Exception("Callback channel is abroted", e); throw exception; } catch (Exception ce) { BrokerTracing.TraceEvent(System.Diagnostics.TraceEventType.Error, 0, "[BrokerClient] Client {0}: Send back response error: {1}", this.clientId, ce); // Reply a fault message indicating failed to send back the response and reply EOR and finish. this.ReplyFaultMessage(callback, FrontEndFaultMessage.GenerateFaultMessage(null, MessageVersion.Default, SOAFaultCode.Broker_SendBackResponseFailed, SR.SendBackResponseFailed), clientData); this.ReplyEndOfMessage(callback, clientData); } finally { // We do not need to lock here because this callback is designed to be // triggered by BrokerQueue synchronizely if (this.cacheBrokerQueueItem) { lock (this.lockCacheItemList) { this.cachedItemList.Add(item); } } else { this.Queue.AckResponse(item, (exception == null)); } if (this.callbackChannelDisposed) { this.Queue.ResetResponsesCallback(); } } }
/// <summary> /// Receive response message from host. /// </summary> /// <param name="data">DispatchData instance</param> public void ReceiveResponse(DispatchData data) { Contract.Requires(data.AsyncResult != null, string.Format(ContractMessageFormat, "DispatchData.AsyncResult")); Contract.Requires(data.Client != null, string.Format(ContractMessageFormat, "DispatchData.Client")); Contract.Requires(data.BrokerQueueItem != null, string.Format(ContractMessageFormat, "DispatchData.BrokerQueueItem")); Contract.Ensures( data.ReplyMessage != null || data.Exception != null, "DispatchData should have either a reply message either an exception."); Message reply = null; string taskId = data.TaskId; DateTime dispatchTime = data.DispatchTime; int clientIndex = data.ClientIndex; IService client = data.Client; BrokerQueueItem item = data.BrokerQueueItem; // Bug #16197: if request action field is dropped by wcf, restore it back if (string.IsNullOrEmpty(item.Message.Headers.Action)) { item.Message.Headers.Action = data.RequestAction; } this.dispatcher.items[clientIndex] = null; this.dispatcher.DecreaseProcessingCount(); Guid messageId = Utility.GetMessageIdFromMessage(item.Message); try { // Get the response message reply = client.EndProcessMessage(data.AsyncResult); data.ReplyMessage = reply; // following method needs to be called before setting bServiceInitalizationCompleted flag this.PostProcessMessage(reply); // mark bServiceInitalizationCompleted flag to true; if (!this.dispatcher.ServiceInitializationCompleted) { this.dispatcher.ServiceInitializationCompleted = true; // nofity that it is connected to service host this.dispatcher.OnServiceInstanceConnected(null); } BrokerTracing.EtwTrace.LogBackendResponseReceived(data.SessionId, taskId, messageId, reply.IsFault); } catch (EndpointNotFoundException e) { data.Exception = e; // TODO: need ExceptionHandler this.dispatcher.HandleEndpointNotFoundException(clientIndex, client, item, messageId, e); return; } catch (StorageException e) { data.Exception = e; // TODO: need ExceptionHandler this.dispatcher.HandleStorageException(dispatchTime, clientIndex, client, item, messageId, e); return; } catch (Exception e) { data.Exception = e; // TODO: need ExceptionHandler this.dispatcher.HandleException(dispatchTime, clientIndex, client, item, messageId, e); return; } if (reply.IsFault) { // If any fault message is received, consider passing binding data again. // TODO: pass binding data only on special error code this.dispatcher.PassBindingFlags[clientIndex] = true; } bool servicePreempted = false; if (reply.IsFault) { BrokerTracing.TraceVerbose( BrokerTracing.GenerateTraceString( "ResponseReceiver", "ReceiveResponse", taskId, clientIndex, client.ToString(), messageId, "The response is a fault message.")); // TODO: need ExceptionHandler data.ExceptionHandled = this.dispatcher.HandleFaultExceptionRetry(clientIndex, item, reply, dispatchTime, out servicePreempted); } else { // if it is a normal response, check if the CancelEvent happens when request is being processed. int index = reply.Headers.FindHeader(Constant.MessageHeaderPreemption, Constant.HpcHeaderNS); if (index >= 0 && index < reply.Headers.Count) { servicePreempted = true; int messageCount = reply.Headers.GetHeader <int>(index); BrokerTracing.TraceVerbose( BrokerTracing.GenerateTraceString( "ResponseReceiver", "ReceiveResponse", taskId, clientIndex, client.ToString(), messageId, string.Format("The count of processing message in the counterpart host is {0}.", messageCount))); // will remove the dispatcher if no processing message left on the host if (messageCount == 0) { // Simulate a SessionFault and reuse the method HandleServiceInstanceFailure, // and the message will be processed later as normal. BrokerTracing.TraceVerbose( BrokerTracing.GenerateTraceString( "ResponseReceiver", "ReceiveResponse", taskId, clientIndex, client.ToString(), messageId, "(Preemption) Call HandleServiceInstanceFailure.")); // TODO: need ServiceInstanceFailureHandler this.dispatcher.HandleServiceInstanceFailure(new SessionFault(SOAFaultCode.Service_Preempted, string.Empty)); } } } data.ServicePreempted = servicePreempted; // Debug Failure Test SimulateFailure.FailOperation(1); }
/// <summary> /// Instantiate a new instance of class GetCallbackContext /// </summary> /// <param name="callback">the callback</param> /// <param name="callbackState">the callback context</param> /// <param name="callbackMsg">the retrieved back message</param> public GetCallbackContext(PersistCallback callback, object callbackState, BrokerQueueItem callbackMsg) { this.callbackField = callback; this.callbackStateField = callbackState; this.callbackMsgField = callbackMsg; }
public override void AckResponse(BrokerQueueItem response, bool success) { throw new NotImplementedException(); }
/// <summary> /// Receive Response /// </summary> /// <param name="item">indicating the broker queue item</param> /// <param name="asyncState">indicating the async state</param> public void ReceiveResponse(BrokerQueueItem item, object asyncState) { BrokerTracing.TraceVerbose("[PullResponsesHandler] Receive response."); XmlDocument doc = new XmlDocument() { XmlResolver = null }; this.resetTimeout(); try { Message soap11Message = this.convertMessage(item.Message); byte[] buffer; MemoryStream ms = null; try { ms = new MemoryStream(); using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(ms)) { var msTemp = ms; ms = null; soap11Message.WriteMessage(writer); writer.Flush(); buffer = msTemp.ToArray(); } } finally { if (ms != null) { ms.Dispose(); } } try { ms = new MemoryStream(buffer); using (XmlReader reader = XmlReader.Create(ms)) { ms = null; doc.Load(reader); } } finally { if (ms != null) { ms.Dispose(); } } this.messages.Add(doc.DocumentElement); if (this.messages.Count >= this.count) { this.completeEvent.Set(); } } finally { this.queue.AckResponse(item, true); } }
private async Task DeserializeMessage(CloudQueueMessage message) { Exception exception = null; BrokerQueueItem brokerQueueItem = null; if (message.AsBytes != null && message.AsBytes.Length > 0) { // Deserialize message to BrokerQueueItem try { brokerQueueItem = (BrokerQueueItem)this.formatter.Deserialize( await AzureStorageTool.GetMsgBody(this.blobContainer, message.AsBytes)); brokerQueueItem.PersistAsyncToken.AsyncToken = brokerQueueItem.Message.Headers.MessageId.ToString(); BrokerTracing.TraceVerbose( "[AzureQueueRequestFetcher] .DeserializeMessage: deserialize header={0} property={1}", brokerQueueItem.Message.Headers.MessageId, brokerQueueItem.Message.Properties); } catch (Exception e) { BrokerTracing.TraceError( "[AzureQueueRequestFetcher] .DeserializeMessage: deserialize message failed, Exception:{0}", e.ToString()); exception = e; } } if (brokerQueueItem != null && !this.requestDic.TryAdd( brokerQueueItem.PersistAsyncToken.AsyncToken.ToString(), true)) { Interlocked.Increment(ref this.pendingFetchCount); try { await this.requestQueue.DeleteMessageAsync(message); } catch (Exception e) { BrokerTracing.TraceError( "[AzureQueueRequestFetcher] .DeserializeMessage: delete duplicate message in request queue failed, Exception:{0}", e.ToString()); } } else { var copyMessage = new CloudQueueMessage(message.AsBytes); await this.pendingQueue.AddMessageAsync(copyMessage); try { await this.requestQueue.DeleteMessageAsync(message); } catch (Exception e) { BrokerTracing.TraceError( "[AzureQueueRequestFetcher] .DeserializeMessage: delete message in request queue failed, Exception:{0}", e.ToString()); } this.HandleMessageResult(new MessageResult(brokerQueueItem, exception)); } }
public MessageResult(BrokerQueueItem message, Exception e) { this.message = message; this.exception = e; }
public override void PutResponseAsync(Message responseMsg, BrokerQueueItem requestItem) { this.replyMessageQueue.Enqueue(responseMsg); }
private void GetWrongMessageTestCallback(BrokerQueueItem persistMessage, object state, Exception exception) { this.IsExpected = persistMessage.Message.GetBody <string>().Equals(wrongMsg); this.CallbackIsCalled = true; }
/// <summary> /// Trigger the callback when called GetRequestAsync /// For UnitTesting purpose /// </summary> /// <param name="item">indicate the broker queue item</param> public void TriggerGetRequestCallback(BrokerQueueItem item) { KeyValuePair <BrokerQueueCallback, object> pair = this.callbackQueue.Dequeue(); pair.Key(item, pair.Value); }
/// <summary> /// Callback function invoked on BeginPeek completion. /// </summary> /// <param name="ar"></param> private void PeekMessageComplete(IAsyncResult ar) { BrokerTracing.TraceVerbose("[MSMQMessageFetcher] .PeekMessageComplete: Peek message complete."); Exception exception = null; System.Messaging.Message message = null; bool needRetry = false; RefCountedCursor storedMessagePeekCursor = ar.AsyncState as RefCountedCursor; this.rwlockMessagePeekCursorField.EnterReadLock(); try { try { // // Check if target queue is disposed. If so, don't call EndPeek. However, the check doesn't guarantee // that msmqQueueField is valid when EndPeek is invoked on it. So ObjectDisposedException shall be handled. // if (this.isQueueDisposed) { BrokerTracing.TraceWarning("[MSMQMessageFetcher]) .PeekMessageComplete: target queue is disposed"); return; } message = this.msmqQueueField.EndPeek(ar); Interlocked.Increment(ref this.peekCursorPosition); } catch (MessageQueueException e) { if (this.isDisposedField) { this.RevertFetchCount(); return; } needRetry = MessageQueueHelper.HandleAsyncCallbackError( e, ref this.messagePeekActionField, "[MSMQMessageFetcher] .PeekMessageComplete: EndPeek message failed, outstandingPeekCount:{0}, messageCount={1}", this.outstandingFetchCount, this.msmqMessageCount); if (!needRetry) { BrokerTracing.TraceError( "[MSMQMessageFetcher] .PeekMessageComplete: end peek message failed, outstandingPeekCount:{0}, messageCount:{1} Exception:{2}", this.outstandingFetchCount, this.msmqMessageCount, e); exception = e; } } catch (Exception e) { if (this.isDisposedField) { this.RevertFetchCount(); return; } BrokerTracing.TraceError("[MSMQMessageFetcher] .PeekMessageComplete: end peek message failed, Exception:{0}", e.ToString()); exception = e; } finally { storedMessagePeekCursor.Release(); } } finally { this.rwlockMessagePeekCursorField.ExitReadLock(); } if (needRetry) { Interlocked.Increment(ref this.pendingFetchCount); return; } if (message == null && exception == null) { BrokerTracing.TraceWarning("[MSMQMessageFetcher] .PeekMessageComplete: EndPeek return null."); } if (message != null) { // if the message is one of the partial messages if (message.AppSpecific > 0 && !string.IsNullOrEmpty(message.Label)) { try { BrokerTracing.TraceVerbose( "[MSMQMessageFetcher] .PeekMessageComplete: peek partial message with AppSpecific {0} and Label {1}.", message.AppSpecific, message.Label); string[] labels = message.Label.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries); string groupId = labels[0]; int msgNumber = int.Parse(labels[1]); ConcurrentDictionary <int, Message> messages = this.partialMessages.GetOrAdd(groupId, (k) => new ConcurrentDictionary <int, Message>()); if (!messages.TryAdd(msgNumber, message)) { BrokerTracing.TraceError( "[MSMQMessageFetcher] .PeekMessageComplete: try add one of the composed messages failed. Message Label {0}.", message.Label); } // check if all partial messages are peeked and cached if (this.partialMessageCounters.AddOrUpdate(groupId, 1, (k, v) => v + 1) == message.AppSpecific) { BrokerTracing.TraceVerbose( "[MSMQMessageFetcher] .PeekMessageComplete: all partial messages are peeked and cached for group {0}.", groupId); Message msg = new Message(); msg.BodyType = message.BodyType; byte[] buffer = new byte[Constant.MSMQChunkSize]; List <long> lookUpIds = new List <long>(message.AppSpecific); for (int i = 1; i <= message.AppSpecific; i++) { Message m = messages[i]; int count = m.BodyStream.Read(buffer, 0, Constant.MSMQChunkSize); msg.BodyStream.Write(buffer, 0, count); lookUpIds.Add(m.LookupId); } msg.BodyStream.Position = 0; BrokerQueueItem brokerQueueItem = null; // Deserialize message to BrokerQueueItem try { brokerQueueItem = (BrokerQueueItem)this.messageFormatter.Read(msg); brokerQueueItem.PersistAsyncToken.AsyncToken = lookUpIds.ToArray(); } catch (Exception e) { BrokerTracing.TraceError( "[MSMQMessageFetcher] .PeekMessageComplete: deserialize message failed for composed messages with groupId {0}, Exception:{1}", groupId, e); exception = e; } messages.Clear(); if (!this.partialMessages.TryRemove(groupId, out messages)) { BrokerTracing.TraceWarning( "[MSMQMessageFetcher] .PeekMessageComplete: try to remove partial messages with groupId {0} from cahce failed.", groupId); } int messageCount; if (!this.partialMessageCounters.TryRemove(groupId, out messageCount)) { BrokerTracing.TraceWarning( "[MSMQMessageFetcher] .PeekMessageComplete: try to remove partial message counters with groupId {0} from cahce failed.", groupId); } this.HandleMessageResult(new MessageResult(brokerQueueItem, exception)); } else { Interlocked.Increment(ref this.pendingFetchCount); } } catch (Exception ex) { BrokerTracing.TraceError( "[MSMQMessageFetcher] .PeekMessageComplete: peek composed message failed, Exception:{0}", ex); } } else { BrokerQueueItem brokerQueueItem = null; // Deserialize message to BrokerQueueItem try { brokerQueueItem = (BrokerQueueItem)this.messageFormatter.Read(message); brokerQueueItem.PersistAsyncToken.AsyncToken = new long[1] { message.LookupId }; } catch (Exception e) { BrokerTracing.TraceError( "[MSMQMessageFetcher] .PeekMessageComplete: deserialize message failed, Exception:{0}", e.ToString()); exception = e; } this.HandleMessageResult(new MessageResult(brokerQueueItem, exception)); } } }
private async Task PeekMessageAsync() { if (this.isDisposedField) { this.RevertFetchCount(); return; } while (true) { Exception exception = null; if (this.pendingFetchCount < 1) { break; } while (this.pendingFetchCount > 0) { byte[] messageBody = null; try { if (responseList == null || responseList.Count <= index) { BrokerTracing.TraceVerbose( "[AzureQueueResponseFetch] .PeekMessageAsync: lastIndex={0}, ackIndex={1}", lastIndex, ackIndex); responseList = await AzureStorageTool.GetBatchEntityAsync( this.responseTable, this.lastIndex, this.ackIndex); index = 0; BrokerTracing.TraceVerbose( "[AzureQueueResponseFetch] .PeekMessageAsync: get batch entity count={0}", responseList.Count); } if (responseList.Count > index) { messageBody = responseList[index].Message; if (long.TryParse(responseList[index].RowKey, out var tempIndex) && tempIndex > this.lastIndex) { this.lastIndex = tempIndex; } index++; } } catch (Exception e) { BrokerTracing.TraceError( "[AzureQueueResponseFetch] .PeekMessageAsync: peek batch messages failed, Exception:{0}", e.ToString()); exception = e; } if (messageBody == null && exception == null) { BrokerTracing.TraceWarning("[AzureQueueResponseFetch] .PeekMessage: null message and exception, lastIndex = {0}, ack = {1}, Count = {2}, index = {3}.", this.lastIndex, this.ackIndex, responseList.Count, index); } else { BrokerQueueItem brokerQueueItem = null; if (messageBody != null && messageBody.Length > 0) { // Deserialize message to BrokerQueueItem try { brokerQueueItem = (BrokerQueueItem)this.formatter.Deserialize( await AzureStorageTool.GetMsgBody(this.blobContainer, messageBody)); brokerQueueItem.PersistAsyncToken.AsyncToken = brokerQueueItem.Message.Headers.RelatesTo.ToString(); BrokerTracing.TraceVerbose( "[AzureQueueResponseFetch] .PeekMessage: deserialize header={0} property={1}", brokerQueueItem.Message.Headers.RelatesTo, brokerQueueItem.Message.Properties); } catch (Exception e) { BrokerTracing.TraceError( "[AzureQueueResponseFetch] .PeekMessage: deserialize message failed, Exception:{0}", e.ToString()); exception = e; } } this.HandleMessageResult(new MessageResult(brokerQueueItem, exception)); Interlocked.Decrement(ref this.pendingFetchCount); } } this.CheckAndGetMoreMessages(); } }