Azure Iot Hub FeedbackReceiver ReceiveAsync is very slow (15 seconds) high latency - azure

if I send a message (Cloud 2 Device) via the IoT-Hub:
var serviceMessage= new Message(Encoding.ASCII.GetBytes("Hello Device"));
serviceMessage.Ack = DeliveryAcknowledgement.Full;
commandMessage.MessageId = Guid.NewGuid().ToString();
await serviceClient.SendAsync("myDeviceID", serviceMessage); //Send message here
And try to receive the acknoledgement from the client:
bool feedbackReceived = false;
while(!feedbackReceived){
FeedbackReceiver<FeedbackBatch> feedbackReceiver = serviceClient.GetFeedbackReceiver();
var feedbackBatch = await feedbackReceiver.ReceiveAsync(TimeSpan.FromSeconds(1));
if(feedbackBatch != null)
{
feedbackReceived = feedbackBatch.Records.Any(fm => fm.OriginalMessageId == serviceMessage.MessageId);
if (feedbackReceived)
{
await feedbackReceiver.CompleteAsync(feedbackBatch);
feedbackReceiver = null;
}
}
}
My client gets the message immediatelly and sends an feedback:
DeviceClient deviceClient = DeviceClient.Create(iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(bridgeID, deviceKey), TransportType.Amqp);
Message receivedMessage = await deviceClient.ReceiveAsync();
await deviceClient.CompleteAsync(receivedMessage);
It take up to 15 seconds until my Cloud gets the feedback.
If I send messages in a loop, then the first message needs something between 1 and 15 sconds and every following response needs exactly 15 seconds.
Why does that need so long? Can I change it?
The receive-method in my cloud gets an answer immediatelly:
var incommingMessage = eventHubReceiver.ReceiveAsync();
incommingMessage.Wait();
If the client sends a message:
var message = new Message(Encoding.ASCII.GetBytes("My Message"));
await deviceClient.SendEventAsync(message);
A whole project with the problem is on gitHub:
https://github.com/Ben4485/Azure_IotHub_Get_Response

Of course 15 seconds are a lot. However, the feedback isn't a single message but always a batch (a JSON document with an array of feedback) that contains more feedbacks from more devices. It's possible that the system tries to acquire more feedback as possible before sending them to the system.
Paolo.

Related

Sending messages to IoT hub from Azure Time Trigger Function as device

At the moment Im simulating device where every 30 seconds I send telemetry data to IoT hub.
Here is simple code:
s_deviceClient = DeviceClient.Create(s_iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(s_myDeviceId, s_deviceKey), TransportType.Mqtt);
using var cts = new CancellationTokenSource();
var messages = SendDeviceToCloudMessagesAsync(cts.Token);
await s_deviceClient.CloseAsync(cts.Token);
await messages;
cts.Cancel();
And function to send message:
string combinedString = fileStrings[0] + fileStrings[1];
var telemetryDataString = converter.SerializeObject(combinedString);
using var message = new Message(Encoding.UTF8.GetBytes(telemetryDataString))
{
ContentEncoding = "utf-8",
ContentType = "application/json",
};
await s_deviceClient.SendEventAsync(message);
await Task.Delay(interval);
Everything works fine and I created .exe file that was running without problems. But computer where code is running tends to shut-off from time to time which is problematic. So I tried to move this to Azure Time Trigger Function. While in logs everything looks ok, messages aren't actually posted to IoT hub.
I tried to find solution but have not been able to find anything. Is it possible to send messages as device with azure function?
You seem to be closing your DeviceClient before you start using it to send messages. Try the following:
public async Task Do()
{
// Using statement will dispose your client after you're done with it.
// No need to close it manually.
using(var client = DeviceClient.Create(s_iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(s_myDeviceId, s_deviceKey), TransportType.Mqtt))
{
// Send messages, await for completion.
await SendDeviceToCloudMessagesAsync(client);
}
}
private async Task SendDeviceToCloudMessagesAsync(DeviceClient client)
{
string combinedString = fileStrings[0] + fileStrings[1];
var telemetryDataString = converter.SerializeObject(combinedString);
using var message = new Message(Encoding.UTF8.GetBytes(telemetryDataString))
{
ContentEncoding = "utf-8",
ContentType = "application/json",
};
await client.SendEventAsync(message);
await Task.Delay(interval);
}

C# as sender and python as receiver in Azure event hub

I have an IoT device that is connected to Azure event hub. I'm trying to make this device communicate with azure databricks and azure event hub is placed in between as a middleware. The problem is that after we are able to send messages via ".NET framework", it is never shown in messages received in "python" command line (we should do that as we work separately for each part)
I followed the guidelines .NET framework as sender and python as receiver, and this doesn't work.
I am seeing that there are spikes in the request and message graphs under event hub stream instances, but it just never shows in the receiver
==================================UPDATE==================================
Just deleted the eventhub and recreated and it seems work.
However, messages are received in the form of long strings something like this below:
Received: 662a2a44-4414-4cb5-a9e9-a08d12a417e0
Received: b68ef8f8-305f-4726-84e4-f35b76de30c5
Received: e94dfb73-972c-47b4-baef-1ab41b06be28
Received: 8eda384d-f79d-4cdf-9db3-fe5c2156553b
Received: d154283f-a8c2-4a4c-a7d5-e8d8129b568d
Received: 3e3e190e-f883-416c-a5be-b8cd8547d152
Received: e218c63b-85b3-4f4f-8f04-cb5ffc6d8921
Received: 0adec5ad-e351-4151-ba56-01093e0f383d
Received 8 messages in 0.05406975746154785 seconds
This happens when I read the messages in format below:
print("Received: {}".format(event_data.body_as_str(encoding='UTF-8')))
I just give it a try, and I can repro your issue. And here are something you need to check.
1.In you sender(in c#), you should make sure your message to send is correct. Like below:
static void SendingRandomMessages()
{
var eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, eventHubName);
int i = 0;
while (true)
{
try
{
// make sure the message is correct.
var message = i+":"+Guid.NewGuid().ToString()+":"+DateTime.Now;
Console.WriteLine("{0} > Sending message: {1}", DateTime.Now, message);
var myeventdata = new EventData(Encoding.UTF8.GetBytes(message));
eventHubClient.Send(myeventdata);
i++;
//eventHubClient.Send(new EventData(Encoding.UTF8.GetBytes(message)));
}
catch (Exception exception)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("{0} > Exception: {1}", DateTime.Now, exception.Message);
Console.ResetColor();
}
Thread.Sleep(2000);
}
}
2.There seems some delay for the receiver(in python), so I execute the python receiver about 3 times, and I can see the expected output. The screenshot as below:
Update 1022: as we discussed in the comment, there is a solution for fixing just receiving even / odd number event data.
In you sender(in c#), use the code below, which sends event data to partition 0:
static void SendingRandomMessages()
{
var eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, eventHubName);
var myclient = eventHubClient.CreatePartitionedSender("0");
int i = 30;
while (true)
{
var message = i + ":" + Guid.NewGuid().ToString() + ":" + DateTime.Now;
Console.WriteLine("{0} > Sending message: {1}", DateTime.Now, message);
var myeventdata = new EventData(Encoding.UTF8.GetBytes(message));
myclient.Send(myeventdata);
i++;
Thread.Sleep(2000);
}
}
then in your receiver(in python), specify the partition to 0(use this PARTITION = "0"), then you can get all the event data.

Get user join / leave events retroactively from Channels

I'm trying to do some analytics on average response time from some of our users on Twilio Chat.
I'm iterating through my channels, and I'm able to pull the info about messages, so I can compare times a message went un-responded to. However, I can't determine which users were in the channel at that time.
Is there anything on the channel that would give me historic member data? Who was in the channel? The channel.messages().list() method is only giving me the text of the messages sent to the channel and who it was by, but the user who may have been in a channel to respond changes throughout a channel's life time.
This is on the backend using the node.js SDK. note: This isn't a complete implementation for what I'm trying to do, but taking it in steps to get access to the information I'd need to do this. Once I have these messages and know which users are supposed to be in a channel at a given time, I can do the analytics to see how long it took for the users I am looking for to respond.
var fs = require('fs');
const Twilio = require('twilio');
const client = new Twilio(env.TWILIO_ACCOUNT_SID, env.TWILIO_AUTH);
const service = client.chat.services(env.TWILIO_IPM_SERVICE_SID);
async function getChatMessages() {
const fileName = 'fileName.csv';
const getLine = message => {
return `${message.channelSid},${message.sid},${message.dateCreated},${message.from},${message.type},${message.body}\n`;
}
const writeToFile = message => { fs.appendFileSync(fileName, getLine(message)); };
const headerLine = `channelSid,messageSid,dateCreated,author,type,body`;
fs.writeFileSync(fileName, headerLine);
await service.channels.each(
async (channel, done) => {
i++;
let channelSid = channel.sid;
if( channel.messagesCount == 0 ) return;
try {
await channel.messages().list({limit:1000, order:"asc"}).then(
messages => {
messages.forEach( writeToFile );
}
);
} catch(e) {
console.log(`There was an error getting messages for ${channelSid}: ${e.toString()}`);
}
if( i >= max ) done();
}
);
}
I'm beginning to be resigned to the fact that maybe this would only have been possible to track had I set up the proper event listeners / webhooks to begin with. If that's the case, I'd like to know so I can get that set up. But, if there's any endpoint I can reach out to and see who was joining / leaving a channel, that would be ideal for now.
The answer is that unfortunately you can not get this data retroactively. Twilio offers a webhooks API for chat which you can use to track this data yourself as it happens, but if you don't capture the events, you do not get access to them again.

Receive only the last message on topics

I have an application subscribed on Azure Servicebus Topic who is constantly receiving messages from Stream Analytics. But this application isn't every time subscribed on this Topic. How do I receive only the last message from the topic when the application do the subscription?
Based on your question and your comments, this is what I can advice you:
When your application starts, connect to the Azure ServiceBus Subscription and get all messages in the queue.
Remove all the previous messages (just complete it) and process the last message.
Then you can start listening to new incoming messages.
Based on this answer (Clearing azure service bus queue in one go) :
// Get the message receiver
var messagingFactory = MessagingFactory.CreateFromConnectionString("ServiceBusConnectionString");
var messageReceiver = messagingFactory.CreateMessageReceiver(SubscriptionClient.FormatSubscriptionPath("TopicName", "SubscriptionName"));
BrokeredMessage lastMessage = null;
while (messageReceiver.Peek() != null)
{
if(lastMessage != null)
{
// This was not the last message so complete it.
lastMessage.Complete();
}
// Batch the receive operation
var brokeredMessages = messageReceiver.ReceiveBatch(300).ToList();
//Get the last message and remove it from the list
lastMessage = brokeredMessages.Last();
brokeredMessages.RemoveAt(brokeredMessages.Count -1);
// Complete all the other messages
var completeTasks = brokeredMessages.Select(m => Task.Run(() => m.Complete())).ToArray();
// Wait for the tasks to complete.
Task.WaitAll(completeTasks);
}
if (lastMessage != null)
{
// Process your message
}
// Start listening to new incoming message
messageReceiver.OnMessage(message =>
{
// Process new messages
}, new OnMessageOptions());

Service Bus Session ReceiveBatchAsync only receiving 1 message

I'm using a Service Bus queue with Sessions enabled and I'm sending 5 messages with the same SessionId. My receiving code uses AcceptMessageSessionAsync to get a session lock so that it will receive all the messages for that session. It then uses session.ReceiveBatchAsync to try and get all the messages for the session. However, it only seems to get the first message, then when another attempt is made, it gets all the others. You should be able to see that there is a gap of almost a minute between the two batches even though all these messages were sent at once:
Session started:AE8DC914-8693-4110-8BAE-244E42A302D5
Message received:AE8DC914-8693-4110-8BAE-244E42A302D5_1_08:03:03.36523
Session started:AE8DC914-8693-4110-8BAE-244E42A302D5
Message received:AE8DC914-8693-4110-8BAE-244E42A302D5_2_08:03:04.22964
Message received:AE8DC914-8693-4110-8BAE-244E42A302D5_3_08:03:04.29515
Message received:AE8DC914-8693-4110-8BAE-244E42A302D5_4_08:03:04.33959
Message received:AE8DC914-8693-4110-8BAE-244E42A302D5_5_08:03:04.39587
My code to process these is a function in a WebJob:
[NoAutomaticTrigger]
public static async Task MessageHandlingLoop(TextWriter log, CancellationToken cancellationToken)
{
var connectionString = ConfigurationManager.ConnectionStrings["ServiceBusListen"].ConnectionString;
var client = QueueClient.CreateFromConnectionString(connectionString, "myqueue");
while (!cancellationToken.IsCancellationRequested)
{
MessageSession session = null;
try
{
session = await client.AcceptMessageSessionAsync(TimeSpan.FromMinutes(1));
log.WriteLine("Session started:" + session.SessionId);
foreach (var msg in await session.ReceiveBatchAsync(100, TimeSpan.FromSeconds(5)))
{
log.WriteLine("Message received:" + msg.MessageId);
msg.Complete();
}
}
catch (TimeoutException)
{
log.WriteLine("Timeout occurred");
await Task.Delay(5000, cancellationToken);
}
catch (Exception ex)
{
log.WriteLine("Error:" + ex);
}
}
}
This is called from my WebJob Main using:
JobHost host = new JobHost();
host.Start();
var task = host.CallAsync(typeof(Functions).GetMethod("MessageHandlingLoop"));
task.Wait();
host.Stop();
Why don't I get all my messages in the first call of ReceiveBatchAsync?
This was answered in the MSDN forum by Hillary Caituiro Monge: https://social.msdn.microsoft.com/Forums/azure/en-US/9a84f319-7bc6-4ff8-b142-4fc1d5f1e2fa/service-bus-session-receivebatchasync-only-receiving-1-message?forum=servbus
Service Bus does not guarantee you will receive the message count you
specify in receive batch even if your queue has them or more. Having
say that, you can change your code to try to get the 100 messages in
the first call, buy remember that your application should not assume
that as a guaranteed behavior.
Below this line of code varclient =
QueueClient.CreateFromConnectionString(connectionString, "myqueue");
add client.PrefetchCount = 100;
The reason that you are getting only 1 message at all times in the
first call is due to that when you accept a session it may be also
getting 1 prefetched message with it. Then when you do receive batch,
the SB client will give you that 1 message.
Unfortunately I found that setting the PrefetchCount didn't have an affect, but the reason given for only receiving one message seemed likely so I accepted it as the answer.

Resources