public void PutResponseAsync(Message responseMsg, BrokerQueueItem requestItem, bool ignoreAsyncToken = false) { try { // Null means the request has been put back. if (responseMsg != null && this.sharedData.Config.LoadBalancing.MessageResendLimit > 0) { if (!requestItem.ReemitToken.Finish()) { TraceUtils.TraceWarning( "BrokerQueueDispatcher", "PutResponseAsync", "Drop the response {0} since no multi emission callback registered", Utility.GetMessageIdFromMessage(requestItem.Message)); return; } } BrokerQueueAsyncToken asyncToken = requestItem.PersistAsyncToken; if (asyncToken.AsyncToken != null || ignoreAsyncToken || responseMsg == null) { asyncToken.Queue.PutResponseAsync(responseMsg, requestItem); return; } DispatcherAsyncTokenItem asyncTokenItem = null; lock (this.requestsAsyncTokenTable) { this.requestsAsyncTokenTable.TryGetValue(asyncToken.PersistId, out asyncTokenItem); } if (asyncTokenItem != null) { bool hasGetAsyncToken = false; try { if (asyncTokenItem != null) { if (asyncTokenItem.AsyncToken != null) { asyncToken.AsyncToken = asyncTokenItem.AsyncToken; hasGetAsyncToken = true; lock (this.requestsAsyncTokenTable) { this.requestsAsyncTokenTable.Remove(asyncToken.PersistId); } } } } catch (Exception e) { if (hasGetAsyncToken) { BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .PutResponseAsync: remove the async token from the table raised the exception, {0}", e); } else { // maybe there are duplicate responses, and the request in the async token table is removed by the previous request. BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .PutResponseAsync: try to get the async token from the table raised the exception, {0}", e); } } if (hasGetAsyncToken) { asyncToken.Queue.PutResponseAsync(responseMsg, requestItem); } else { BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PutResponseAsync: Failed to get async token."); lock (this.responsesWithoutAsyncTokenTable) { this.responsesWithoutAsyncTokenTable.Add(asyncToken.PersistId, new DispatcherAsyncTokenItem(responseMsg, asyncToken)); } if (asyncTokenItem.AsyncToken != null) { bool needPutToTheQueue = false; try { lock (this.responsesWithoutAsyncTokenTable) { this.responsesWithoutAsyncTokenTable.Remove(asyncToken.PersistId); } needPutToTheQueue = true; lock (this.requestsAsyncTokenTable) { this.requestsAsyncTokenTable.Remove(asyncToken.PersistId); } } catch (Exception e) { if (needPutToTheQueue) { BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PutResponseAsync: remove the request async token from the table failed, the exception: {0}", e); } else { // in case the reponse message is persisted by another thread. BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PutResponseAsync: remove the response from the responses without async table fail, the exception: {0}", e); } } if (needPutToTheQueue) { asyncToken.AsyncToken = asyncTokenItem.AsyncToken; asyncToken.Queue.PutResponseAsync(responseMsg, requestItem); } else { BrokerTracing.TraceWarning( "[BrokerQueueDispatcher] .PutResponseAsync: Don't put response back because needPutToTheQueue=false. AsyncToken.PersistId={0}, requestItem id: {1}, response id:{2}", asyncToken.PersistId, requestItem?.Message?.Headers?.MessageId, responseMsg?.Headers?.MessageId); } } else { // the request item is processed and its response is returned, but its async token is unknown yet. At this point, as corresponding DispatcherAsyncToken item is // already put into responsesWithoutAsyncTokenTable, the request item itself is of no use now. so dispose it. BrokerTracing.TraceInfo( "[BrokerQueueDispatcher] .PutResponseAsync: Dispose requestItem id: {0}, response id:{1}", requestItem?.Message?.Headers?.MessageId, responseMsg?.Headers?.MessageId); requestItem.Dispose(); } } } else { BrokerTracing.TraceError("[BrokerQueueDispatcher] .PutResponseAsync: can not find the async token."); } } catch (Exception e) { BrokerTracing.TraceError("[BrokerQueueDispatcher] .PutResponseAsync: unkown exception, {0}", e); } }