/// <summary> /// Run the worker process. Creates a connection to the RabbitMQ broker and processes the received messaged. /// </summary> /// <param name="autoResetEvent">Reset event to signals the method to exit.</param> /// <exception cref="InvalidOperationException">Thrown if the RabbitMQ connection cannot be resolved.</exception> public void Run(AutoResetEvent autoResetEvent) { IConnection connection = ServiceProvider.GetService(typeof(IConnection)) as IConnection; if (connection == null) { throw new InvalidOperationException("RabbitMQ IConnection service not configured"); } using (var channel = connection.CreateModel()) { ChannelHelper.EnsureQueue(ActionCode, channel); channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: true); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var props = ea.BasicProperties; var replyProps = channel.CreateBasicProperties(); RequestMessage request = SerializationHelper.FromBytes <RequestMessage>(ea.Body); ResponseMessage response = null; replyProps.CorrelationId = props.CorrelationId; try { XElement data = Process(request); response = ResponseMessage.CreateResponseOK(data); } catch (Exception ex) { response = ResponseMessage.CreateResponseERROR(ex); } finally { if (response != null) { var responseBytes = SerializationHelper.ToBytes(response); channel.BasicPublish(exchange: "", routingKey: props.ReplyTo, basicProperties: replyProps, body: responseBytes); } channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); } }; channel.BasicConsume(queue: ActionCode, autoAck: false, consumer: consumer); autoResetEvent.WaitOne(); } }
public RpcClient(IConnection rmqConnection) { clientID = Guid.NewGuid().ToString("N"); actionCodes = new List <string>(); tasksDict = new ConcurrentDictionary <string, TaskCompletionSource <ResponseMessage> >(); connection = rmqConnection; channel = connection.CreateModel(); ChannelHelper.EnsureQueue(ReplyQueueName, channel, true); consumer = new EventingBasicConsumer(channel); consumer.Received += Consumer_Received; channel.BasicConsume(queue: ReplyQueueName, autoAck: true, consumer: consumer); }
/// <summary> /// Publish message to the message broker. /// </summary> /// <param name="request">Request object instance.</param> /// <param name="secondsTimeout">Number of seconds to wait for action completion.</param> /// <returns>Response generated from remote action execution.</returns> /// <exception cref="TimeoutException">Exception raised when the action does not completes before the timeout period.</exception> public Task <ResponseMessage> Execute(RequestMessage request, int secondsTimeout = 15) { var correlationId = Guid.NewGuid().ToString("N"); var completionSource = tasksDict.GetOrAdd(correlationId, new TaskCompletionSource <ResponseMessage>()); var bytes = SerializationHelper.ToBytes(request); var props = channel.CreateBasicProperties(); props.DeliveryMode = 2; props.CorrelationId = correlationId; props.ReplyTo = ReplyQueueName; if (!actionCodes.Contains(request.ActionCode)) { ChannelHelper.EnsureQueue(request.ActionCode, channel); actionCodes.Add(request.ActionCode); } channel.BasicPublish( exchange: "", routingKey: request.ActionCode, basicProperties: props, body: bytes); Task.WhenAny(completionSource.Task, Task.Delay(secondsTimeout * 1000)).ContinueWith(t => { if (!completionSource.Task.IsCompleted) { if (tasksDict.TryRemove(correlationId, out TaskCompletionSource <ResponseMessage> source)) { source.SetException(new TimeoutException()); } } }); return(completionSource.Task); }