private static void LogReceivedRpcResponse(IPublisherContext context, CreatedExchange createdExchange, object responseObj) { var definition = createdExchange.Definition; context.Logger.LogTraceDetails( $"Response to RPC message sent to queue: {definition.QueueMeta.QueueName} on bus: {definition.BusName}", responseObj); }
// Add properties used by the receiving consumer required for sending // the response to the reply queue. private void AppendRpcMessageProperties(MessageProperties msgProps, CreatedExchange createdExchange) { msgProps.ReplyTo = ReplyToQueueName; msgProps.CorrelationId = msgProps.CorrelationId ?? Guid.NewGuid().ToString(); msgProps.SetRpcReplyBusConfigName(_busName); msgProps.SetRpcActionNamespace(createdExchange.Definition.ActionNamespace); }
public async Task Publish(IPublisherContext context, CreatedExchange createdExchange, IMessage message, CancellationToken cancellationToken) { // Prepare the message and its defining properties to be published. byte[] messageBody = context.Serialization.Serialize(message, createdExchange.Definition.ContentType); MessageProperties messageProperties = GetMessageProperties(context, createdExchange, message); string routeKey = message.GetRouteKey() ?? createdExchange.Definition.RouteKey; // Only send the message to the exchange if satisfying all constraints configured for the exchange. // This only applies to domain-events, as commands are more specific in that they are explicitly // requesting a behavior to be taken. if (message is IDomainEvent && !await Satisfies(context, createdExchange, message).ConfigureAwait(false)) { return; } // Delegate to EasyNetQ to publish the message. await createdExchange.Bus.Advanced.PublishAsync(createdExchange.Exchange, routeKey ?? string.Empty, false, messageProperties, messageBody).ConfigureAwait(false); }
private void LogRpcPublishDetails(CreatedExchange createdExchange, string correlationId) { string receiverQueue = createdExchange.Definition.QueueMeta.QueueName; string actionNs = createdExchange.Definition.ActionNamespace; _logger.LogDebug("Sending RPC message with Correlation Id: {correlationId} to Receiver Queue: {receiverQueue} " + "having Action Namespace: {requestNs}. Will receive response on Reply Queue: {replyQueueName}.", correlationId, receiverQueue, actionNs, ReplyToQueueName); }
private static async Task <bool> Satisfies(IPublisherContext context, CreatedExchange createdExchange, IMessage message) { ExchangeMeta definition = createdExchange.Definition; bool applies = definition.Applies(message); if (applies && definition.ScriptPredicate != null) { return(await context.Scripting.SatisfiesPredicateAsync(message, definition.ScriptPredicate)); } return(applies); }
public async Task Publish(IPublisherContext context, CreatedExchange createdExchange, IMessage message, CancellationToken cancellationToken) { ICommand command = (ICommand)message; string contentType = createdExchange.Definition.ContentType; // Serialize the message and get the properties from the default-publisher to be used as // the initial list of message properties to which RPC specific properties will be added. byte[] messageBody = context.Serialization.Serialize(command, contentType); MessageProperties messageProperties = DefaultPublisherStrategy.GetMessageProperties(context, createdExchange, command); // Get the RPC client associated with the exchange to which the RPC message is being sent. IRpcClient client = context.PublisherModule.GetRpcClient( createdExchange.Definition.BusName, createdExchange.Definition.QueueMeta.QueueName); // Note: Consumer replies with same content-type that was used to publish command. try { // Delegate to the client to send the request and wait for response in reply queue. byte[] resultBytes = await client.Publish(createdExchange, messageBody, messageProperties, cancellationToken).ConfigureAwait(false); // If a successful reply, deserialize the response message into the // result type associated with the command. var responseObj = context.Serialization.Deserialize(contentType, command.ResultType, resultBytes); command.SetResult(responseObj); LogReceivedRpcResponse(context, createdExchange, responseObj); } catch (RpcReplyException ex) { // If the consumer didn't supply details about the exception, then just rethrow. if (ex.ReplayExceptionBody == null) { throw; } var dispatchEx = context.Serialization.Deserialize <MessageDispatchException>(contentType, ex.ReplayExceptionBody); context.Logger.LogError(RabbitMqLogEvents.PublisherException, dispatchEx, "RPC Exception Reply."); throw dispatchEx; } }
public static MessageProperties GetMessageProperties(IPublisherContext context, CreatedExchange createdExchange, IMessage message) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (createdExchange == null) { throw new ArgumentNullException(nameof(createdExchange)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } var definition = createdExchange.Definition; var props = new MessageProperties { ContentType = definition.ContentType, AppId = context.BusModule.HostAppId, Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), DeliveryMode = (byte)(definition.IsPersistent ? 2 : 1) }; string correlationId = message.GetCorrelationId(); if (correlationId != null) { props.CorrelationId = correlationId; } byte?msgPriority = message.GetPriority(); if (msgPriority != null) { props.Priority = msgPriority.Value; } return(props); }
public async Task <byte[]> Publish(CreatedExchange createdExchange, byte[] messageBody, MessageProperties messageProperties, CancellationToken cancellationToken) { if (createdExchange == null) { throw new ArgumentNullException(nameof(createdExchange)); } if (messageBody == null) { throw new ArgumentNullException(nameof(messageBody)); } if (cancellationToken == null) { throw new ArgumentNullException(nameof(cancellationToken)); } AppendRpcMessageProperties(messageProperties, createdExchange); // Create a task that can be completed in the future when the result // is received in the reply queue. var futureResult = new TaskCompletionSource <byte[]>(); string correlationId = messageProperties.CorrelationId; int cancelRpcRequestAfterMs = createdExchange.Definition.CancelRpcRequestAfterMs; var rpcPendingRequest = new RpcPendingRequest(futureResult, cancellationToken, cancelRpcRequestAfterMs); _pendingRpcRequests[correlationId] = rpcPendingRequest; string routeKey = createdExchange.Definition.QueueMeta.QueueName; LogRpcPublishDetails(createdExchange, correlationId); // Publish the command to the exchange. await createdExchange.Bus.Advanced.PublishAsync(createdExchange.Exchange, routeKey, false, messageProperties, messageBody).ConfigureAwait(false); try { // This task will be completed when the response to the command is received on // on the reply queue. The task result is the bytes of the response message. return(await futureResult.Task); } catch (TaskCanceledException ex) { // If the pending request task has been canceled, remove the pending // request and unregister the cancellation delegate. if (_pendingRpcRequests.TryRemove(correlationId, out RpcPendingRequest pendingRequest)) { pendingRequest.UnRegister(); } throw new RpcReplyException( $"The RPC request with the correlation value of: {correlationId} was canceled. " + $"The current timeout value is: {cancelRpcRequestAfterMs} ms.", ex); } catch (Exception ex) { if (_pendingRpcRequests.TryRemove(correlationId, out RpcPendingRequest pendingRequest)) { pendingRequest.UnRegister(); } throw new RpcReplyException( "The RPC request with the correlation value of: {correlationId} resulted in an exception.", ex); } }