Yes, so even if you create these Consumer
object instances on separate threads, their respective handler events will fire on the same thread (as verified in your provided logs screenshot). This is because in .NET, objects are not bound to a specific thread regardless of how they are instantiated, and that at the networking layer, the Solace client library initially dispatches all messages on a shared thread to ensure message (and client events) are handled in-order.
If you wish for each consumer instance to process messages separately from the others, there are numerous patterns you can use (such as Task chaining or Channels ) but here is a-super simple, older style approach which spins up a thread instance per consumer:
private IFlow flow;
private BlockingCollection<MessageEventArgs> messageEvents;
private Thread processThread;
public QueueConsumer()
{
messageEvents = new BlockingCollection<MessageEventArgs>();
// Other startup and initialization logic such has creating the IFlow instance…
// flow = …
processThread = new Thread(new ThreadStart(ProcessMessage))
{
IsBackground = true
};
processThread.Start();
}
void HandleMessageEvent(object source, MessageEventArgs args)
{
messageEvents.Add(args);
}
private void ProcessMessage()
{
while (true)
{
var args = messageEvents.Take();
// Process the message here...
// Ack message when done
flow.Ack(args.Message.ADMessageId);
}
}
This example takes messages as they are received and sends them to a BlockingCollection<T>
instance where they are picked up on a dedicated and persistent processing thread.
Regarding your question on partitions: yes, you should never have more consumers (devices, processes, or flows) than number of partitions unless you want them to sit in standby mode should another consumer go down.