TL;DR: the bot takes 2-9 seconds to send any message to the user, even if I send the message from the very first line in MessagesController.cs.
I have used the Bot Framework to create a couple of bots for Facebook Messenger and I noticed that one of them is significantly slower than the other.
Both bots have the code below as the very first lines in the MessagesController.cs. This is supposed to send the Typing indicator to the user.
One bot consistently takes 2 seconds to show this typing indicator to the user on Facebook, while the other takes 9 seconds.
Activity typing = activity.CreateReply(null);
typing.ServiceUrl = activity.ServiceUrl;
typing.Type = ActivityTypes.Typing;
ConnectorClient connector = new ConnectorClient(new Uri(typing.ServiceUrl));
await connector.Conversations.SendToConversationAsync(typing);
The second bot indeed does much more work (calling various web APIs), but since these lines are the very first in the controller, I expect the typing indicator to be sent to the user immediately, after which the bot can continue doing its work.
However, it seems that the messages (including the typing indicator) are not sent until the bot completes its work.
Is there a way to "flush" the messages to the user to have a typing indicator sent immediately, or am I encountering some other issue?
Update: I've tried the ConnectorClient.Dispose() method but it doesn't seem to help make it any faster to send messages.
I am not sure what you mean by "flushing" the messages to the user but your bot should show the typing indicator immediately until you type a message and there is some process in the background. To avoid processing information until the user types a message you can use the ActivityTypes like this:
if (activity.Type == ActivityTypes.Message)
{
Activity typing = activity.CreateReply(null);
typing.ServiceUrl = activity.ServiceUrl;
typing.Type = ActivityTypes.Typing;
ConnectorClient connector = new ConnectorClient(new Uri(typing.ServiceUrl));
await connector.Conversations.SendToConversationAsync(typing);
}
else
{
HandleSystemMessage(activity);
}
...
However, it makes sense that the user cannot type anything until the application has already given a answer back to the previous question.
Related
Let's imagine that we have Q named "NotificationQ" and have a consumer who gets a task from that Q and sends emails to customers.
Emailing process sends an email by API from mailgun. That API request does not turn 200 every time(the reason is not important). In that time I need to tell RabbitMQ that tasks fail. I know there is a feature called autoAck but if a request fails how the RabbitMQ client pack understood that a fail.
Am I manually trigger ack to say that request failed?
I using https://www.nuget.org/packages/RabbitMQ.Client/ pack to handle RabbitMQ tasks.
var channel = RabbitPrepareFactory.GetConnectionFactory();
channel.BasicQos(0, 1, false);
var notificationPack = channel.BasicGet("notification", true);
var message = System.Text.Encoding.UTF8.GetString(notificationPack.Body.ToArray());
var task = JsonConvert.DeserializeObject<ForgetPasswordEmailNotification>(message);
var isEmailSendSuccessful = SomeFakeEmailSendFunctions(task.Email);
if (!isEmailSendSuccessful)
{
//something for tell RabbitMQ that task fail and not delte that task in q
.......
}
I think this could be usefull. I would use something like a Dead Letter
https://www.rabbitmq.com/dlx.html
So everytime a message is failing for whatever reason, you push the message to that queue.
Once your messaged was recieved by your consumer and the scope of the operation finished, that message is acknowledged so that other consumers will not take a already processed message.
[Edit]
I dont't think its a good ideea to process a message from a queue and afterwards to leave it there if something happens to your BackEnd. If you implement the dead letter queue you could try to reprocess those messages at some time ( Maybe a CronJob ) or if you really don't wanna have dead letter queues you could try to implement in your Client a Retry Mechanism. Polly could work very well in your case https://github.com/App-vNext/Polly
I am using the following libraries to connect a bot to a Google Pub/Sub endpoint to perform a simple reply to a card click event.
Google.Apis.HangoutsChat.v1 1.34.0.1233
Google.Cloud.PubSub.V1 1.0.0-beta18
When I construct my card, everything looks normal in the UI, including the button that is supposed to raise the event.
The topic and subscription contain the default settings, following the guide here
I found the following information from the Google documentation about retries here
Responding synchronously
A bot can respond to an event synchronously by returning a
JSON-formatted message payload in the HTTP response. The deadline for
a synchronous response is 30 seconds.
A synchronous response from a bot is always posted in the thread that
generated the event to the bot.
After clicking the button, my subscriber receives 3 duplicate events. The events have the correct response with all of the right metadata, but are exact duplicates of each other, including the id of the message itself.
I don't feel there is a necessarily large delay in the response of the bot (it should happen in <1 second for this test), so I am not sure why these messages are being duplicated.
I've also tried setting the thread id for the card when responding (via the Thread property itself, or the ThreadKey property), but I always seem to get a new thread id when I post a message.
var cardMessage = MessageSender.Spaces.Messages.Create(new Message()
{
Space = new Space()
{
Name = inReplyToThisMessage.Space.Name
},
Thread = new Thread()
{
Name = inReplyToThisMessage.Thread.Name
},
Cards = new List<Card>()
{
card
},
}, inReplyToThisMessage.Space.Name);
var sendCardResult = await cardMessage.ExecuteAsync().ConfigureAwait(false);
//Thread id of sendCardResult does not match inReplyToThisMessage.Thread.Name no matter what
Interestingly enough, trying to create a new message in response to the click event causes the bot to display a "Unable to connect to bot. Try again later", but displays 3 new messages. Also, when specifying an arbitrary thread key, this key is never echoed back in the bot's response.
Make sure you are returning the main event method properly. What looks to be happening is that you are making an asynchronous call to the chat, but then the chat is looking for a response from the actual event method itself. Google will traditionally try three times before giving up (even if it doesn't take thirty seconds)
If you are indeed returning the event call correctly after you made your api request, then there is something in your code that is causing the Google Bot to think it is not getting a response, so it tries three times. Since the issue could be multi-faceted I would need to look at how you are accepting and returning the click response.
This bug has finally been fixed by Google.
I am attempting to create a bot that has the ability to delete only the bots messages after a command has been done.
I am aware of how i know that the command has taken place however I am having issues with only deleting the messages that the bot has sent.
await Message.ModifyAsync(msg => msg.Content = "test [edited]");
However this only occurs to the last message that has been sent (This can be fixed relatively easily and I know how to do this) and importantly would otherwise occur to all the messages in the chat! What i want to do is make it so that I only delete messages that were sent by the bot in the first place.
Thanks
Get and store the message that the bot sent as a variable, and delete it later.
var botMsg = await ReplyAsync("A message!");
await botMsg.DeleteAsync();
If you need to delete multiple messages, create a list and store each message to the list. Then use await Context.Channel.DeleteMessagesAsync(list) at the end of the command.
EDIT
There are overload methods for passing both list of message ID and the message itself.
Example of passing a list of message ID:
List<ulong> msgToDel = new List<ulong>();
msgToDel.Add((await ReplyAsync("test1")).Id); //Send a msg, then add the msg ID to the list.
msgToDel.Add((await ReplyAsync("test2")).Id);
//Blah...
await Context.Channel.DeleteMessagesAsync(msgToDel);
You can check the documentation for the DeleteMessagesAsync() here.
The normal expected behaviour for the code below, would be that ReceiveAsync, looks at the Azure queue for up to 1 minute before returning null or a message if one is received. The intended use for this is to have an IoT hub resource, where multiple messages may be added to a queue intended for one of several DeviceClient objects. Each DeviceClient will continuously poll this queue to receive message intended for it. Messages for other DeviceClients are thus left in the queue for those others.
The actual behaviour is that ReceiveAsync is immediately returning null each time it's called, with no delay. This is regardless of the value that is given with TimeSpan - or if no parameters are given (and the default time is used).
So, rather than seeing 1 log item per minute, stating there was a null message received, I'm getting 2 log items per second (!). This behaviour is different from a few months ago,. so I started some research - with little result so far.
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Client;
public static TimeSpan receiveMessageWaitTime = new TimeSpan(0, 1 , 0);
Microsoft.Azure.Devices.Client.Message receivedMessage = null;
deviceClient = DeviceClient.CreateFromConnectionString(Settings.lastKnownConnectionString, Microsoft.Azure.Devices.Client.TransportType.Amqp);
// This code is within an infinite loop/task/with try/except code
if(deviceClient != null)
{
receivedMessage = await deviceClient.ReceiveAsync(receiveMessageWaitTime);
if(receivedMessage != null)
{
string Json = Encoding.ASCII.GetString(receivedMessage.GetBytes());
// Handle the message
}
else
{
// Log the fact that we got a null message, and try again later
}
await Task.Delay(500); // Give the CPU some time, this is an infinite loop after all.
}
I looked at the Azure hub, and noticed 8 messages in the queue. I then added 2 more, and neither of the new messages were received, and the queue is now on 10 items.
I did notice this question: Azure ServiceBus: Client.Receive() returns null for messages > 64 KB
But I have no way to see whether there is indeed a message that big currently in the queue (since receivemessage returns null...)
As such the questions:
Could you preview the messages in the queue?
Could you get a queue size, e.g. ask the number of messages in the queue before getting them?
Could you delete messages from the queue without getting them?
Could you create a callback based receive instead of an infinite loop? (I guess internally the code would just do a peek and the same as we are already doing)
Any help would be greatly appreciated.
If you use the Azure ServiceBus, I recommend that you could use the Service Bus Explorer to preview the message, get the number of message in the queue. And Also you could delete the message without getting them.
This may seem like an odd question, but is there a way to send a local toast notification from a Windows 8 Store App to the machine--and NOT show it on the screen? I have a background task that needs to send a sync request to the UI thread. I have been searching for the better part of 8 hours trying to get different methods to work--and it comes down to this will work for me, but I don't want the request text to show up on the screen when I call it.
I should also add that Toast Notifications WILL be used in the app, so I can't simply turn it off globally, I need only the ones I specify to not show up, to be hidden. Is this possible?
Ideally, I would rather do a Raw Notification, but I can't figure out how to do a local Raw Notification (of if its even possible to simulate it without hitting my API.).
EDIT: Root Problem
My background task is doing work behind the scenes every 15 minutes--to basically send a sync request to the main app. The OnPushNotificationReceived, should capture this and perform a full sync of all data I need: Such as GPS coordinates, checking if "ToDoItems" are nearing due dates and need to be escalated in priority, etc. Among other things, such as checking if there are any documents on the local file system that have been marked as complete and need to be uploaded to Azure file storage, etc.
The answer might be in the OnPushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
args.Cancel = true
From MSDN: https://msdn.microsoft.com/en-us/library/br241295
Cancel:
Read/write Gets or sets whether Windows should perform its default handling of the notification.
You receive the notification and process it in your OnPushNotificationReceived listener, set the cancel to true and voila!
Basically you already processed the notification, so you cancel the default behaviour that is showing the notification.
EDIT CONTENT:
The Raw Notification basically is an empty envelope where you can put any content in any form you want, could be an object, an image, a dictionary... Basically you decide the content to send and obviously the app must know the datamodel to be able to process it.
To create Notifications easily I recommend you this Nuget Package: https://github.com/WindowsNotifications/NotificationsExtensions/tree/master/Windows%208.1%20RT
Example on how to create a toast notifcation:
var toastNoti = ToastContentFactory.CreateToastText02();
toastNoti.TextHeading.Text = "TEXT IN BOLD";
toastNoti.TextBodyWrap.Text = "TEXT IN NORMAL CASE ";
toastNoti.Launch = "NOTIFICATION ARGUMENTS";
var doc = new XmlDocument();
doc.LoadXml(toastNoti.ToString());
var endNotification = new ToastNotification(doc);
endNotification.Tag = "1";
ToastNotificationManager.CreateToastNotifier().Show(endNotification);
Hope this helps. Tell us any result please.