protected virtual async Task <TResponseMessage> SendInternal <TResponseMessage>(IRequestMessage <TResponseMessage> request, TimeSpan?timeout, string topic, CancellationToken cancellationToken) { if (Settings.RequestResponse == null) { throw new PublishMessageBusException("An attempt to send request when request/response communication was not configured for the message bus. Ensure you configure the bus properly before the application starts."); } // check if the cancellation was already requested cancellationToken.ThrowIfCancellationRequested(); var requestType = request.GetType(); var publisherSettings = GetPublisherSettings(requestType); if (topic == null) { topic = GetDefaultTopic(requestType, publisherSettings); } if (timeout == null) { timeout = GetDefaultRequestTimeout(requestType, publisherSettings); } var replyTo = Settings.RequestResponse.Topic; var created = CurrentTime; var expires = created.Add(timeout.Value); // generate the request guid var requestId = GenerateRequestId(); var requestPayload = SerializeRequest(requestType, request, requestId, replyTo, expires); // record the request state var requestState = new PendingRequestState(requestId, request, requestType, typeof(TResponseMessage), created, expires, cancellationToken); PendingRequestStore.Add(requestState); if (Log.IsTraceEnabled) { Log.TraceFormat("Added to PendingRequests, total is {0}", PendingRequestStore.GetCount()); } try { Log.DebugFormat("Sending request message {0} to topic {1} with reply to {2} and payload size {3}", requestState, topic, replyTo, requestPayload.Length); await PublishToTransport(requestType, request, topic, requestPayload); } catch (PublishMessageBusException e) { Log.DebugFormat("Publishing of request message failed: {0}", e); // remove from registry PendingRequestStore.Remove(requestId); throw; } // convert Task<object> to Task<TResponseMessage> var typedTask = Convert <TResponseMessage>(requestState.TaskCompletionSource.Task); return(await typedTask); }
protected virtual void CleanPendingRequests(object sender, ElapsedEventArgs args) { var now = CurrentTime; var requestsToCancel = PendingRequestStore.FindAllToCancel(now); foreach (var requestState in requestsToCancel) { // request is either cancelled (via CancellationToken) or expired var canceled = requestState.CancellationToken.IsCancellationRequested ? requestState.TaskCompletionSource.TrySetCanceled(requestState.CancellationToken) : requestState.TaskCompletionSource.TrySetCanceled(); if (PendingRequestStore.Remove(requestState.Id) && canceled) { Log.DebugFormat("Pending request timed-out: {0}, now: {1}", requestState, now); // ToDo: add and API hook to these kind of situation } } }
/// <summary> /// Performs cleanup of pending requests (requests that timed out or were cancelled). /// </summary> public virtual void CleanPendingRequests() { var now = CurrentTime; var requestsToCancel = PendingRequestStore.FindAllToCancel(now); foreach (var requestState in requestsToCancel) { // request is either cancelled (via CancellationToken) or expired var canceled = requestState.CancellationToken.IsCancellationRequested ? requestState.TaskCompletionSource.TrySetCanceled(requestState.CancellationToken) : requestState.TaskCompletionSource.TrySetCanceled(); if (PendingRequestStore.Remove(requestState.Id) && canceled) { Log.DebugFormat("Pending request timed-out: {0}, now: {1}", requestState, now); // Execute the event hook // ToDo: sort out the ConsumerSettings arg for req/resp, for now pass null (Settings.RequestResponse.OnMessageExpired ?? Settings.OnMessageExpired)?.Invoke(null, requestState.Request); } } }