I have successfully setup a facebook-messenger webhook. Until yesterday I was able to send and receive messages as well. But today, when I am sending one message from user, I am getting multiple calls at server webhook POST API. They never seem to stop.
Do all of those calls have the same content or are they different? You could log the exact message string that facebook sends to you and see what they include.
For example there's a message delivery callback that informs you that the user received the message. The JSON looks like this:
{'delivery': {'mids': ['mid.146174459xxx:30a42600a95exxxxx'], 'seq': 429, 'watermark': 146174459xxx}, 'recipient': {'id': xxxxxxxx}, 'sender': {'id': xxxxxx}}
Edit: It could also be the case that your are not confirming incoming calls with a http status 200. If facebook receives an error from your webhook the message will be sent multiple times.
Figured it out. I was sending response to every communication that came from facebook. So I ended up responding to ACK messages as well. In turn one more ACK came. Thats why it led to infinite loop.
In this page we can find different object structures for messages recieved:
text
{
"object":"page",
"entry":[
{
"id":PAGE_ID,
"time":1457764198246,
"messaging":[
{
"sender":{
"id":USER_ID
},
"recipient":{
"id":PAGE_ID
},
"timestamp":1457764197627,
"message":{
"mid":"mid.1457764197618:41d102a3e1ae206a38",
"seq":73,
"text":"hello, world!"
}
}
]
}
]
}
Message-Delivered callback
{
"object":"page",
"entry":[
{
"id":PAGE_ID,
"time":1458668856451,
"messaging":[
{
"sender":{
"id":USER_ID
},
"recipient":{
"id":PAGE_ID
},
"delivery":{
"mids":[
"mid.1458668856218:ed81099e15d3f4f233"
],
"watermark":1458668856253,
"seq":37
}
}
]
}
]
}
So, for differentiating we can refer to entry[0].messaging[0].message this exist only in user sent message. Callback or postbacks do not contain this part.
Check for this, before responding. If it exists, respond, otherwise dont.
My problem was similar but I was getting Multiple Message delivery posts. After a few hours of frustration, I realized that Message Delivered callback is called every time the message is delivered to EVERY DEVICE. So, if you are logged into both web and mobile app, the callback would be called twice.
When working with messenger of facebook you need to take in account two things after you send the message :
A) Message Delivery
B) Message Read
Since you are working with webhooks this will be trigger everytime one of the events happen (receive a message , deliver the message you sent , the user read the message). So if you activate for example message_deliveries in your webhook and you send a message as action , you will end up in a loop.
The proper way to handle this is in the base code. PHP example :
// Skipping delivery messages
if (!empty($message['delivery'])) {
#Do something here if you want
continue;
}
// Skipping read messages
if (!empty($message['read'])) {
#Do something here if you want
continue;
}
Hope it helps !
Related
I've configured monolog to send errors via email as described in the symfony docs here: https://symfony.com/doc/4.3/logging/monolog_email.html
Works well with all errors happing during a request, as well as console command errors.
But it does not send emails for errors which occurred during the handling of a messenger message.
Errors are shown when running the consumer bin/console messenger:consume async -vv and they also show up in prod.log like this:
[2020-01-10 12:52:38] messenger.CRITICAL: Error thrown while handling message...
Thanks for any hints on how to set up monolog to get messenger errors emailed too.
In fact monolog swift_mailer type use SwiftMailerHandler
wish also implements reset interface and use memory spool by default wish keep all emails in buffer until it is destructed, so till the end of request :
onKernelTerminate
onCliTerminate
OR till reset method is called, which means that for messenger worker no emails will be send ever because ther's no instant flush - all of them will be kept in in-memory buffer, and probably lost if the process will be killed.
To solve this, you can just disable the default spool memory setting for swiftmailer.
Another solution is to flush your emails after WorkerMessageFailedEvent event gets fired, you can implement an event subscriber to do it for this.
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
use Symfony\Contracts\Service\ResetInterface;
/**
* Class ServiceResetterSubscriber.
*/
class ServiceResetterSubscriber implements EventSubscriberInterface
{
protected ResetInterface $servicesResetter;
public function __construct(ResetInterface $servicesResetter)
{
$this->servicesResetter = $servicesResetter;
}
public function resetServices(): void
{
$this->servicesResetter->reset();
}
public static function getSubscribedEvents(): array
{
return [
WorkerMessageFailedEvent::class => ['resetServices', 10],
];
}
}
Register your service with the right argument:
App\EventSubscriber\ServiceResetterSubscriber:
arguments: ['#services_resetter']
By the way without this (and without buffer limit) your app will leak and no emails will be sent ever.
Another trick:
Make sure that your message implements \JsonSerializable to get the message content in your logs, because messenger uses his monolog directly and its context serializer wish use json_encode for seriliazation.
That's why we need to customize their JSON representation when encoded is done with json_encode.
I am having problems with the event handler in my office addin . Below is an example code i got from microsoft website to explain what i mean.
I have a manifest file that uses the on-send hook as well as a click-based event triggering.
My button calls appendMessageBodyOnClick and onsend i call appendMessageBodyOnSend. Both function primarily do the same thing. I never want to block sending emails regardless.
The problem is that the event object is not properly cleaned up i think.
Scenario 1
When i click my button ; which calls event.completed(), and then after i try to send the message, it says my app is blocking the message, but then when i try to send again it goes through.
Scenario 2
When i leave the subject empty and then send the message, as expected i am prompted that the subject is empty. If i cancel sending the message on this note and then click on my button, the message tries to send as though i clicked send.
I am supposing the is some sort or state clean up issue. What am i doing wrong here?
Function-File.js
function appendMessageBodyOnClick(event) {
// Append string to message body
event.completed();
}
// In the following example, the checkMessage function has
// been registered as an event handler for ItemSend.
function appendMessageBodyOnSend(event) {
// Append string to message body
event.completed({allowEvent = true});
}
Not sure if this will help, but I also have faced some seemingly inconsistent behavior while understanding how to signal that event is fully completed. Once I got my edge cases fixed, then it worked.
One suggestion: Appending string to message body should be an async function. Call the event.completed() from inside the callback function. (i.e: make sure when you are calling event.completed(), nothing else is pending -like another async result)
Something like the following:
Office.context.mailbox.item.body.setAsync("new body", function(asyncResult) {
// handle success and failure
event.completed()
});
Same would be for your scenario 2, make sure event.completed() is called at the very end.
I am trying to get a way to see if a message that i get using the Outlook Rest API using this url https://graph.microsoft.com/beta/me/messages('{messageid}') and seing if it is a reply. Normaly it would be from the Thread Id but the API doesn´t send one.
Is there anyway to see if the message is a reply?
API has one 'ConversationId' field. You can use that to group the messages.
{
...
"ConversationId": "AQQkADAwAT..."
...
}
This question has been answered here:
https://stackoverflow.com/a/60048538/3892957
Use GET https://graph.microsoft.com/v1.0/me/messages?$expand=SingleValueExtendedProperties($filter=(Id%20eq%20'Integer%200x1081'))
If a Message had been replied to you would see a result like
"singleValueExtendedProperties": [
{
"id": "Integer 0x1081",
"value": "102"
}
]
I'm currently trying to get an idea of getting Facebook's RSVP for an event, but really stuck on that part:
as I see now, to get user's RSVP I have to make three requests with the following logic:
request eventID/attending/userID ->
if "data" array count == 0 ->
request eventID/maybe/userID ->
if "data" array count == 0 ->
request eventID/declined/userID
else -> means user didn't make any choice previously.
So here it looks like I have to make 3 requests to facebook's graph api to get users's RSVP for a single event.
The question is if there is any way to get an RSVP status for an event doing a single request?
I'm using the latest Facebook SDK and the latest graph api.
Many thanks in advance.
So the best solution here so far is:
one request to /eventID/attending/userID
one request to /eventID/maybe/userID
one request to /eventID/declined/userID (if needed to know if the event invitation was declined)
Call to eventID/attending(maybe/declined)/userID lets us filter rsvp to single user, so we avoid downloading and processing a large amount of data here.
After call you have two options:
If result is true, you get the following response:
{
"data": [
{
"name": "Oleskii Poplavlen",
"id": "10204715567996406",
"rsvp_status": "attending"
}
]}
If result is false, you get the following response:
{
"data": []
}
So while you still have to make multiple requests to get user's RSVP to event, you can avoid downloading loads of other users's rsvps.
Hope that helps someone!
I can get you started to do it in 2 calls:
FB.api('/'+ event_id + '?fields=id,attending{rsvp_status},maybe{rsvp_status}', function(event_response){
// here you should make a call to check if the user has the event and if so get the rsvp_status
FB.api('/'+ user_id + '/events?fields=id,rsvp_status', function(user_response){
// check if user has event, then log the rsvp_status
if(user_response.id == event_response.id) {
console.log(user_response.rsvp_status);
} else {
console.log("user is not going");
});
});
I have not tested this but I've been playing around with this API for quite a while now. This could be an answer to do it in 2 calls, not in 1 unfortunatly.
The first call doesn't need the 'attending' and 'maybe' fields but it's usefull to test with.
Hi am using this function that works by a single ID (52000121) and comma separatted ID's (5000000,500002,500004,000002001)
function invite(id) {
FB.ui({method: 'apprequests',
message: '<?=get_texto_clave('wants_you_to_join')?>',
title: '<?=get_texto_clave('send_app_request')?> <?=$_SESSION['alias']?>',
to: id,
}, function(response){
if(response!=null){
var invitados = id.split(',');
for( i=0; i<invitados.length; i++){
$('#friend_'+invitados[i]).addClass('invited');
$('#friend_'+invitados[i]+' .inviteButton').addClass('invitedBtn').text('<?=get_texto_clave('Invitado')?>');
}
}
});
}
Wich seems to be working fine,
But I have just sent more than 500 invites to friends of mine, and they all got the 'ivited' class (When i completed the popup);
¿Did they all recived it?
I know the response debugging could be better, but still would like to know if user can send an invite to all of his friends same day no matter how many friends are. Or is there any user/app limitation?
Thanks
There is a no limit to the app requests you send
But if you use multi friend selector, you can select maximum of 50 and 25 in IE.
Naturally, if you're being spammy, you'll still get reported a lot and automated systems could block you, so remember to keep to a reasonable volume of requests.
Btw, You can read the response to know to whom it was delivered.