I need to process a message queue (at up to 200 messages per second).
After processing a message, it needs to be published to 2 or 3 other queues.
Service.PublishMessage creates a new
MessageProducer for each request. This opens a new connection to the MQ broker, which adds a large overhead and significantly slows down the rate I can process messages.
If the message handler returns a response DTO, this will be published to the ResponseDtoName.inq using the same MQ client that consumed the message from the queue, so there is no additional overhead.
Do you have any suggestions for increasing performance in this scenario?
Is it possible to give the message handler access to the underlying MQ client, e.g.:
public class ActivityService : Service
public object Post(RecordActivityRequest request)
//process message ...
//How can I get access to the MQ client here?
var mqClient = Request.GetCurrentMqClient(); //Would return null if source of request is not MQ
You can get access to the MessagePublisher with:
var mqPublisher = base.MessageProducer;
Or a MQ Client with:
var mqClient = base.TryResolve<IMessageService>().MessageFactory
To check if a Request is an MQ Request you can do:
var isMqRequest = base.Request is `BasicRequest`;
Looks like I wasn't clear.
will create a new MQ client for every request handled by the service (because
Service is request scoped).
If I use
ServiceController.ExecuteMessage to handle a message from a queue, a new instance of my service will be instantiated for each message (as per the usual request pipeline).
If I am handling hundreds of messages per second and calling
base.PublishMessage in my service, this will result in hundreds of new
MessageProducers being created per second.
Creating a new
MessageQueueClient) opens a new TCP connection to the RabbitMQ server (using the underlying RabbitMQ client library).
If I try this, my message processing throughput drops by 50-75%.
Not exactly sure what you're after then, the above is how you can create a MQ Client in your Service. It's not ThreadSafe to share the same client instance across multiple Services so that's not going to work. Ideally RabbitMQ would pool the underlying client connections (that's how most network services maximize resources). Without connection pooling, (if it works in your use-case) you may be able to create "Batch" Services where clients publish multiple messages at once.
Alternatively you can try use a custom wrapper instance that uses
[ThreadStatic] MQ Client instances or a singleton instance behind a global lock to make it Thread Safe. The cleanest/most transparent approach is to implement/register a custom
IMessageFactory which implements client connection pooling behind the scenes so when the client is disposed it's released back into a pool - but a pooled connection factory can be tricky to implement a robust implementation from scratch.