/// <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)); }
/// <summary> /// Initializes a new instance of the GetMessageState class. /// </summary> /// <param name="messageCallback">the callback that get the message</param> /// <param name="callbackState">the callback state object.</param> public GetMessageState(PersistCallback messageCallback, object callbackState) { if (messageCallback == null) { throw new ArgumentNullException("messageCallback"); } this.messageCallbackField = messageCallback; this.callbackStateField = callbackState; }
public void Persist() { Log.Instance.LogFineDebug(string.Format("TaskListGroup.Persist")); if (PersistCallback != null) { PersistCallback.OnPersist(); } else { Log.Instance.LogInfo(string.Format("TaskListGroup.Persist - PersistCallback is null, skipping")); } }
/// <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 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(); }
/// <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; }