/// <summary> /// Threadpool callback that invokes callback of GetMessageAsync call /// </summary> /// <param name="state">callback state of the threadpool callback</param> private void GetMessageAsyncCallback(object state) { object[] objs = (object[])state; GetMessageState getMessageState = objs[0] as GetMessageState; MessageResult result = objs[1] as MessageResult; try { if (getMessageState.MessageCallback != null) { getMessageState.MessageCallback(result.Message, getMessageState.CallbackState, result.Exception); } } catch (Exception e) { BrokerTracing.TraceError( "[MSMQMessageFetcher] .GetMessageAsyncCallback: perform the message callback failed, the exception, {0}", e.ToString()); } }
private void GetMessageAsyncCallback(object state) { object[] objs = (object[])state; GetMessageState getMessageState = objs[0] as GetMessageState; MessageResult result = objs[1] as MessageResult; try { if (getMessageState.MessageCallback != null) { getMessageState.MessageCallback(result.Message, getMessageState.CallbackState, result.Exception); } } catch (Exception e) { BrokerTracing.TraceError( "[AzureQueueMessageFetcher] .GetMessageAsyncCallbck: fetcherId={0} perform the message callback failed, the exception, {1}", this.fetcherId, e); } }
public void GetMessageAsync(PersistCallback callback, object state) { if (this.isDisposedField) { BrokerTracing.TraceWarning( "[AzureQueueMessageFetcher] .GetMessageAsync: fetcherId={0} the instance is disposed.", this.fetcherId); return; } BrokerTracing.TraceVerbose( "[AzureQueueMessageFetcher] .GetMessageAsync: fetcherId={0} Get message come in.", this.fetcherId); // GetMessageAsync: // step 1, try to get message from prefetch cache. If succeeded, invoke the callback directly; or else, // step 2, save context of this GetMessageAsync call, including callback and callback state into this.currentGetMessageState, which will be handled when a message is retrieved back from MSMQ. // step 3, check if need to get more messages. If so, initiate more BeginPeek calls into MSMQ GetMessageState getMessageState = new GetMessageState(callback, state); MessageResult result = null; Queue <MessageResult> messageQueue = new Queue <MessageResult>(); #if DEBUG bool getResponse = false; #endif long getMessageCount = 1; ResponseCallbackItem responseCallbackItem = state as ResponseCallbackItem; if (responseCallbackItem != null) { #if DEBUG getResponse = true; #endif getMessageCount = responseCallbackItem.ExpectedResponseCount; Debug.WriteLine( $"[AzureQueueMessageFetcher] .GetMessageAsync: working to get response. getMessageCount={getMessageCount}."); } else { Debug.WriteLine( $"[AzureQueueMessageFetcher] .GetMessageAsync: working to get request. getMessageCount={getMessageCount}."); } this.lockPrefetchCache.EnterReadLock(); try { if (this.prefetchCache == null) { // this instance is disposed BrokerTracing.TraceWarning( "[AzureQueueMessageFetcher] .GetMessageAsync: the instance is disposed."); return; } while (getMessageCount > 0) { if (!(this.prefetchCache.Count > 0 && this.prefetchCache.TryDequeue(out result))) { BrokerTracing.TraceVerbose("[AzureQueueMessageFetcher] .GetMessageAsync: cache miss"); result = null; this.currentGetMessageQueue.Enqueue(getMessageState); break; } BrokerTracing.TraceVerbose("[AzureQueueMessageFetcher] .GetMessageAsync: hit cache"); messageQueue.Enqueue(result); getMessageCount--; } } finally { this.lockPrefetchCache.ExitReadLock(); } Debug.WriteLine( $"[AzureQueueMessageFetcher] .GetMessageAsync: getMessageCount={getMessageCount} after dequeue."); while (messageQueue.Any()) { var message = messageQueue.Dequeue(); if (message != null) { // There is one more space available in prefetch cache lock (this.lockFetchCount) { this.prefetchCredit++; } // GetMessageAsync is a light-weight call and is supposed to return very soon. While in its callback, // there may be time-consuming operations. So here we always invoke the callback in another thread. ThreadPool.QueueUserWorkItem( this.GetMessageAsyncCallback, new object[] { getMessageState, message }); } else { BrokerTracing.TraceWarning( "[AzureQueueMessageFetcher] .GetMessageAsync: fetcherId={0} encountered null message result.", this.fetcherId); } } this.CheckAndGetMoreMessages(); }
protected void HandleMessageResult(MessageResult messageResult) { lock (this.lockFetchCount) { this.outstandingFetchCount--; if (messageResult.Message != null) { this.messageCount--; } } GetMessageState getMessageState = null; this.lockPrefetchCache.EnterUpgradeableReadLock(); bool TryGetMessageFromQueue(out GetMessageState state) { state = null; return(this.currentGetMessageQueue != null && this.currentGetMessageQueue.TryDequeue(out state)); } try { if (this.prefetchCache == null) { // this instance is disposed return; } if (!TryGetMessageFromQueue(out getMessageState)) { this.lockPrefetchCache.EnterWriteLock(); try { if (!TryGetMessageFromQueue(out getMessageState)) { getMessageState = null; this.prefetchCache.Enqueue(messageResult); } } finally { this.lockPrefetchCache.ExitWriteLock(); } } } finally { this.lockPrefetchCache.ExitUpgradeableReadLock(); } if (getMessageState != null) { lock (this.lockFetchCount) { this.prefetchCredit++; } ThreadPool.QueueUserWorkItem( this.GetMessageAsyncCallback, new object[] { getMessageState, messageResult }); } this.CheckAndGetMoreMessages(); }