This is more of a conceptual question and doesn't apply to any particular programming language.
I have two entities communicating with each other, with three types of messages allowed:
Command Message: An unsolicited message commanding the other entity to do something.
Query Message: An unsolicited message asking the other entity for information.
Response Message: A solicited message answering a query message from the other entity.
Now each entity has two threads:
Reader Thread: Reads messages.
Worker Thread: Sends messages and does useful things
The two possible communication scenarios are:
Entity A sends a command to Entity B, and Entity A doesn't care what happens after.
Entity A sends a query to Entity B, and Entity A must wait until Entity B responds with the answer.
So the question is, how does the reader thread handle both solicited and unsolicited messages?
Unsolicited messages are easy to handle through events. The reader thread can just fire an event on the worker thread saying it received a query or a command, and the worker thread can react accordingly.
Solicited messages are hard to handle though. The worker thread sends a query, and must block until it receives a response or times out. How does the worker thread let the reader thread know it is waiting for a response, and how does the reader thread tie a response back to a specific query from the worker thread and deliver that response back to the worker thread's execution?
I know this has been done a million times in other programs, so whats the standard practice?
[I used Windows Azure Service Bus messaging entities as I am familiar with it, but in general this should be true with any Messaging system.]
Lets say your entity names are A and B.
Have 1 Topic (pub-sub entities) and 1 Queue for communication between A and B (as you need bidirectional communication) : Topic-A2B & Queue-B2A. A2B is for Commands from A to B or Queries from A to B and B2A, as the name says, is for Responses from B to A.
Typical Messaging Systems will offer MessageType property - for you to be able to set it and the later distinguish which type of messages you are reading and route it accordingly : Example from Windows Azure ServiceBus Brokered Message. Use that Property - to set whether its a Query or Command or Response.
The idea here is - while receiving a message in B - you will receive using Subscriptions. You will have 2 threads reading - (one) reads only Commands (theSecondOne) reads only Queries
For UnSolicited messages - as you said, its easy to handle. All you need to do is
A should send message to B with BrokeredMsg.ContentType="Cmd" and B should create a Subscription with a filter and read and process
For Solicited Messages - like Queries (a feature called Sessions will come handy here).
A should send Message to B with something like: BrokeredMessage.ContentType = "Query"
A also sets a correlation Id on the Message it sends to B: BrokeredMessage.SessionId = "ABC456" <-- The Correlation Id for A to be able to correlate this message with
Now A will wait for response and expects B to also set
BrokeredMessage.SessionId="ABC456" <--- The exact same value it had set earlier.
using the AcceptMessageSession API - with the Session Id and a Timeout. Ex: Q_B2A_QClient.AcceptMessageSession("ABC456", 2 mins)
At the receiving end B should Create a Subscription with a filter to be able to Receive these messages.
Once B receives the query - it processes and puts back the result in the Q-BToA
If B succeeds to put back the message in the Q-B2A in less than 2 Mins - then A will receive it and then you can orchestrate it further with a Callback method (as all of these are async methods - you will not need to use any Reader or Writer thread as you mentioned above - which will be a huge performance booster).
HTH!
Sree
Related
When publishing messages to a service bus topic, if I loop over 3 messages:
{ A, B, C }
And await the SendAsync() each time, I'd expect them to be published to the topic in the order:
{ A, B, C }
public async Task PublishMessage(string topic, string json, string sessionId)
{
var topicClient = new TopicClient(_connectionString, topic);
var busMessage = new Message(Encoding.UTF8.GetBytes(json));
busMessage.SessionId = sessionId;
await topicClient.SendAsync(busMessage);
}
A number of employees have suggested this isn't guaranteed to be the case, and that in certain scenarios (i.e large messages), this publishing order isn't guaranteed. I've never encountered a scenario of this myself, does ASB not guarantee publish ordering even when the sending of messages is awaited like the above?
This article https://devblogs.microsoft.com/premier-developer/ordering-messages-in-azure-service-bus/ uses this quote:
"While Azure Service Bus allows for a FIFO approach (First-In-First-Out), we cannot guarantee that messages are entered in the order we want them to be processed"
This all seems quite baffling to me, as I'd have assumed SendAsync() would only return a successful result once the message has been added into the topic. Do we really need to write layers of complexity around this to manage it?
Please note this only relates to the publishing of messages, we use SessionIds to handle consumption.
Even if you wait for one message to be sent and then only send the next one, the FIFO is not guaranteed. This is due to too many probable causes. In order to ensure you get guaranteed ordering, you need to use session enabled queues or subscriptions.
I try to receive messages from Devices with the "EventHubReceiver" (Device2Cloud). Each device should have it's own, single receiver.
It isn't a problem to create one single EventHubReceiver (per Partition) for all devices:
string iotHubconnectionString = CloudConfigurationManager.GetSetting("Microsoft.IotHub.ConnectionStringPayed");
string iotHubD2cEndpoint = "messages/events";
EventHubClient eventHubClient = EventHubClient.CreateFromConnectionString(iotHubconnectionString, iotHubD2cEndpoint);
EventHubRuntimeInformation runtimeInformation = eventHubClient.GetRuntimeInformation();
If I then want to receive messages from the clients I do the following steps:
EventHubReceiver eventHubReceiver = eventHubClient2.GetDefaultConsumerGroup().CreateReceiver(partition); //Get the partitions via the runtimeInformation: string[] partitions = runtimeInformation.PartitionIds;
var incommingMessage = eventHubReceiver.ReceiveAsync(); //Wait here for incomming messages
That works all right, but all messages from all "Devices" arrive then at this one "EventHubReceiver". I would like to have multiple receiver, that only receive messages from a single device.
I tried to change the following codeline:
string iotHubD2cEndpoint = "messages/events";
to
string iotHubD2cEndpoint = "devices/{deviceID}/messages/events";
but that doesn't work all right. I get the following error:
The link address 'devices/secondDevice/messages/events/$management' did not match any of the expected formats. Supported formats: '/$cbs', '/devices/{deviceid}/messages/events', '/devices/{deviceid}/messages/deviceBound', '/messages/deviceBound', '/messages/serviceBound/feedback', '/messages/events/*'.
So the problem is that I get 'devices/secondDevice/messages/events/$management' insted of 'devices/secondDevice/messages/events/'
I don't know, whether it is just not possible to create a single EventHubReceiver for each Device or I've got a error in the code or thinking.
When a device send telemetry data to IoT Hub, the events are made available to the related D2C endpoint in the cloud that is "event hub compatible".
It has an "event hub like" behaviour and for this reason we are able to get message using an EventHubReceiver.
However, event hubs works in partitions and the incoming message can be assigned to partitions in a round robin fashion or hashing a partition key.
In the IoT Hub architecture I don't know if it use round robin but it's possibile that it use to hash the device id (as partition key) so all messages from a device go into a partition. It doesn't mean that the partition contains messages only for that device ! It's impossible to have a partition for each device :-)
So ... a partition containes messages mixed from different device (but message from a specific device go always in the same partition). An Event Hub receiver can read from partition so it gets all messages from more device. You need to distinguish them based on device id.
I forgot to mention, that I've already got a solution. But it is not very nice:
All deviceThreads (one for each partition and device) wait ("WaitOne") at one point (locked with AutoResetEvent)
I receive all messages with a single receiver
I put the message into a own queue for each device (Dictionary that contains as key a object of the device(id and partition) and as value a List
I set a single thread set free with the "set" command.
The thread looks in its queue and:
if there is a message in the queue it continues and returns the result with a "yield return" -> waits again for a new message
else it sets a different thread fee and returns to the freeze state
All threads loop in a while(true) to wait for messages.
The solution is working, but it doesn't look very performant (with many threads) and a bit complicated.
I need to limit the rate of consuming messages from rabbitmq queue.
I have found many suggestions, but most of them offer to use prefetch option. But this option doesn't do what I need. Even if I set prefetch to 1 the rate is about 6000 messages/sec. This is too many for consumer.
I need to limit for example about 70 to 200 messages per second. This means consuming one message every 5-14ms. No simultaneous messages.
I'm using Node.JS with amqp.node library.
Implementing a token bucket might help:
https://en.wikipedia.org/wiki/Token_bucket
You can write a producer that produces to the "token bucket queue" at a fixed rate with a TTL on the message (maybe expires after a second?) or just set a maximum queue size equal to your rate per second. Consumers that receive a "normal queue" message must also receive a "token bucket queue" message in order to process the message effectively rate limiting the application.
NodeJS + amqplib Example:
var queueName = 'my_token_bucket';
rabbitChannel.assertQueue(queueName, {durable: true, messageTtl: 1000, maxLength: bucket.ratePerSecond});
writeToken();
function writeToken() {
rabbitChannel.sendToQueue(queueName, new Buffer(new Date().toISOString()), {persistent: true});
setTimeout(writeToken, 1000 / bucket.ratePerSecond);
}
I've already found a solution.
I use module nanotimer from npm for calculation delays.
Then I calculate delay = 1 / [message_per_second] in nanoseconds.
Then I consume message with prefetch = 1
Then I calculate really delay as delay - [processing_message_time]
Then I make timeout = really delay before sending ack for the message
It works perfectly. Thanks to all
See 'Fair Dispatch' in RabbitMQ Documentation.
For example in a situation with two workers, when all odd messages are heavy and even messages are light, one worker will be constantly busy and the other one will do hardly any work. Well, RabbitMQ doesn't know anything about that and will still dispatch messages evenly.
This happens because RabbitMQ just dispatches a message when the message enters the queue. It doesn't look at the number of unacknowledged messages for a consumer. It just blindly dispatches every n-th message to the n-th consumer.
In order to defeat that we can use the prefetch method with the value of 1. This tells RabbitMQ not to give more than one message to a worker at a time. Or, in other words, don't dispatch a new message to a worker until it has processed and acknowledged the previous one. Instead, it will dispatch it to the next worker that is not still busy.
I don't think RabbitMQ can provide you this feature out of the box.
If you have only one consumer, then the whole thing is pretty easy, you just let it sleep between consuming messages.
If you have multiple consumers I would recommend you to use some "shared memory" to keep the rate. For example, you might have 10 consumers consuming messages. To keep 70-200 messages rate across all of them, you will make a call to Redis, to see if you are eligible to process message. If yes, then update Redis, to show other consumers that currently one message is in process.
If you have no control over consumer, then implement option 1 or 2 and publish message back to Rabbit. This way the original consumer will consume messages with the desired pace.
This is how I fixed mine with just settimeout
I set mine to process consume every 200mls which will consume 5 data in 1 seconds I did mine to do update if exist
channel.consume(transactionQueueName, async (data) => {
let dataNew = JSON.parse(data.content);
const processedTransaction = await seperateATransaction(dataNew);
// delay ack to avoid duplicate entry !important dont remove the settimeout
setTimeout(function(){
channel.ack(data);
},200);
});
Done
My application (.NET-based) gets messages from a queue in a multithreaded fashion and I'm worried about the fact that I may receive messages in an out-of-order manner because one thread can be quicker than the other, for instance, given the following queue state:
[Message-5 | Message-4 | Message-3 | Message-2 | Message-1]
In a multithreaded operation, msg #2 may arrive before msg #1, even though msg #1 was first in the queue, due to many threading issues (thread time slices, thread scheduling etc).
In such a situation, it would be great if a message that is inside the queue have already stamped with an ordinal/sequence number when it was enqueued and even if I get the messages in an out of order fashion, I can still order them at some point within my application using their given ordinal-number attribute.
Any known mechanism to achieve it in a Websphere MQ environment?
You have 2 choices:
(1) Use Message Grouping in MQ as whitfiea mentioned or
(2) Change you application to be single threaded.
Note: If the sending application does not set the MQMD MsgId field then the queue manager will generate a unique number (based on queue manager name, date & time) and store it in the message's MQMD MsgID field.
You can obtain the MessageSequenceNumber from the MQMessage if the messages are put to the queue in a message group. The MessageSquenceNumber will either be the order that the messages were put to the queue by default or defined by the application that put the messages to the queue.
See the MessageSequenceNumber here for more details
Yes, if the originating message has an ordinal then as you receive your data you could:
Use a thread safe dictionary:
SortedDictionary<int,Message>
It's known that, in cases when one needs comunicate between UI thread and working thread, an hidden window must be created because of thread safety(handle reconstruction).
For exemplify:
Form1 has N dynamicaly created TProgressBar instances with the same name of a background running .
Is always garanteed that WM_REFRESH will only be called inside Task Thread.
Form1 has H : THandle property that allocates the following procedure:
procedure RefreshStat(var Message: TMessage); message WM_REFRESH;
Inside RefreshStat, in cases when there is only 1 background thread I could easily use L and W parameter to map Task Id and position.
I don't know if the title says what I want to know, but let's imagine if we have an application that has multiple background tasks running.
In my case I use TProgressBar to report progress the done.
Does AllocateHwnd garantee that all messages arrives with no race condition the hidden window?
What happens if two or more tasks post the message at the same time?
If this needs to be controled manually, I wonder if there is something else to do besides creating another message loop system in the custom message.
I hope the question is clear enough.
The message queue associated with a thread is a threadsafe queue. Both synchronous and asynchronous messages from multiple other thread are delivered safely no harmful date races. There is no need for any external synchronization when calling the Windows message API functions like SendMessage and PostMessage.
If two threads post or send messages to the same window at the same time, then there is no guarantee as to which message will be processed first. This is what is known as a benign race condition. If you want one message to be processed before the other then you must impose an ordering.