16

I'm playing around with building a simple Facebook Messenger chatbot and I'm having trouble sending messages in sequence.

enter image description here

In the example above, it should have printed "Hello!", "1", "2", "3" in order. I'm currently following the Facebook docs found here to implement this simple text message function. I've included my Express Node.JS server code below:

Defining the sendTextMessage() function:

var request = require("request");
function sendTextMessage(user, text) {
    messageData = {
        text: text
    };
    request({
        url: "https://graph.facebook.com/v2.6/me/messages",
        qs: {access_token: PAGE_ACCESS_TOKEN},
        method: "POST",
        json: {
            recipient: {id: user},
            message: messageData
        }
    }, function(error, response, body) {
        if (error) {
            console.log("Error sending message: ", error);
        } else if (response.body.error) {
            console.log("Error: ", response.body.error);
        } else {
            console.log("Message successfully send.")
        }
    });
}

Using it to send a response:

sendTextMessage(user, "Hello!");
sendTextMessage(user, "1");
sendTextMessage(user, "2");
sendTextMessage(user, "3");

I even tried implementing a simple queue that queues messages and only sends one message at a time after each request's success callback. This is making me suspect that I'm not interacting with the Messenger API correctly.

Has anyone encountered this issue? How can I get messages to send in sequence? Thanks!

EDIT

Because I implemented a simple queue but still experiencing this problem, I'm including the code for my simple queue system here.

var queue = [];
var queueProcessing = false;

function queueRequest(request) {
    queue.push(request);
    if (queueProcessing) {
        return;
    }
    queueProcessing = true;
    processQueue();
}

function processQueue() {
    if (queue.length == 0) {
        queueProcessing = false;
        return;
    }
    var currentRequest = queue.shift();
    request(currentRequest, function(error, response, body) {
        if (error || response.body.error) {
            console.log("Error sending messages!");
        }
        processQueue();
    });
}

queueRequest(/* Message 1 */);
queueRequest(/* Message 2 */);
queueRequest(/* Message 3 */);

UPDATE

This "bug" was reported to Facebook but it sounds like they aren't going to fix it. Please read the ticket thread on Facebook's post here for details on what they say is going on. (Thank you to Louise for getting Facebook's attention on this)

Brian
  • 7,955
  • 16
  • 66
  • 107
  • @brain did you find any work around? – Nagaraju Jul 25 '16 at 10:27
  • @Raju I didn't find an explicit solution yet, but if you look below, someone did file a bug report for it and I believe it's being worked on. I was able to sort of work around it by implementing an arbitrary 1 second delay between sending messages by recursively using `setTimeout` on a queue of messages. It works, but it seems like a hack. Hope that helps! – Brian Jul 25 '16 at 20:38
  • We solved it using this https://www.npmjs.com/package/fibers – Nagaraju Jul 27 '16 at 03:51
  • Thanks for the queue code! It's a simple little solution :) – Tony Anziano Oct 13 '16 at 04:50
  • I just implemented a queuing system that seems to solve this issue, and I did it in a similar way to this. – Alex McCabe Feb 01 '17 at 10:14
  • Did you try sending a 200 response within 15 seconds? I've [seen this](http://stackoverflow.com/a/37510885/873177) that mentions the same issue. – Stephen Tetreault Feb 20 '17 at 17:08
  • No I haven't, but that could be a potential approach. I'm not longer working on this project at this time, but this thread seems to continue getting views so hopefully other people stumbling upon this will find it helpful. – Brian Feb 23 '17 at 00:50
  • has this been fixed? – Rohan Sood Jun 21 '17 at 09:07
  • @RohanSood I'm no longer working on this project so I haven't been following it anymore. The last thing I know about this issue is that someone created a bug report to Facebook devs and they responded by saying this was a non-issue and it won't be fixed: https://developers.facebook.com/bugs/565416400306038. The thread on Facebook's developer website should be able to offer you more help as to what the official response from Facebook is. Hope that answers your question! – Brian Jun 21 '17 at 18:45
  • this happen because of nodejs nature.If you are using node.js and send multiple messages with callbacks it is very likely it going to get random order since it happens asynchronously. – Nyi Nyi Oct 12 '18 at 11:08

11 Answers11

10

I submitted a bug report to Facebook about this because I was having the same problem. They acknowledged that it is indeed a bug and are working to fix it: https://developers.facebook.com/bugs/565416400306038

Louise
  • 151
  • 1
  • 8
4

After you send a POST to /me/messages, you'll receive a response that has a message id (mine start with 'mid.' which maybe stands for message id?):

{ recipient_id: '1015411228555555',
  message_id: 'mid.1464375085492:b9606c00ca33c12345' }

After being completely received by the FB Messenger API, you'll get a call to your webhook (with no message events) that confirms receipt:

{ sender: { id: '1015411228555555' },
  recipient: { id: '566031806XXXXXX' },
  delivery:
   { mids: [ 'mid.1464375085492:b9606c00ca33c12345' ],
     watermark: 1464375085604,
     seq: 176 } }

I think that delivery receipt is the best way to ensure delivery, then send the next message.

younglion
  • 190
  • 1
  • 9
  • 2
    My mistake, according to newer Facebook developer notes the delivery receipts are not guaranteed and though this might work well for some dev environments this technique won't actually be a good approach in prod. We're currently implementing a delay though there must be some better way of dealing with this, even at scale. – younglion Jul 29 '16 at 20:00
2

Implement the send request as a Promise and only send consequent messages once the previous one is resolved

const send = (userId, messageData)  => {

      return new Promise((resolve, reject) => {
        request
        (
            {
                url     : BASE_URL + "me/messages",
                qs      : { access_token : PAGE_ACCESS_TOKEN },
                method  : "POST",
                json    : 
                        {
                            recipient: { id : userId },
                            message: messageData,
                        }
            }, (error, response, body) => 
            {
                if (error) { console.log("Error sending message: " + response.error); return reject(response.error); }
                else if (response.body.error) { console.log('Response body Error: ' + response.body.error); return reject(response.body.error); }

                console.log("Message sent successfully to " + userId); 
                return resolve(response);
            }
        );    
    });
};
ninjadave
  • 56
  • 4
2

You can achieve QUEUING by promises.

function delay(time) {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve, time);
  });
}

delay(2000).then(() => {
  console.log('hi');
  delay(2000).then(() => {
    console.log('hello');
    delay(2000).then(() => {
      console.log('welcome');
    })
  })
})
Akshay Bande
  • 2,491
  • 2
  • 12
  • 29
1

Instead of adding static timeouts, I would create a queue data structure. When the bot wants to send a message, append the contents to the end of the queue. On the message post callback, check if there are any messages still in the queue and call the function again using recursion and remove from the queue accordingly.

Corn Doggo
  • 66
  • 7
  • As I mentioned at the bottom of my post, I tried implementing a queue where I would recursively send messages in the queue that after each successful send callback. That surprisingly still didn't work. – Brian May 14 '16 at 04:40
  • @Brian is the bot and receiving end on the same network? Perhaps the retrieval is so instantaneous that message order is jumbled upon download. – Corn Doggo May 14 '16 at 05:34
  • I'm using messenger.com as my "client" where I'm interacting with the bot. The bot itself is running as a Node.js app on Heroku servers. – Brian May 15 '16 at 07:52
  • @Brian I'd have to do research on it, but my best guess would be that the messenger backend is actually asynchronous too and not dependent on the "sent" times but rather the time that the backend distributes them to the receiving end, so it would be unreliable to send them even in a queue format. Perhaps you could attempt the queue system and add an arbitrary delay before handling the next in the queue? At least that would give it a small buffer for the backend to handle a request. You could also determine to send the next one based on delivery times, but that's unrelated... – Corn Doggo May 15 '16 at 08:00
  • 1
    Thanks Chase, I'm surprised I wasn't able to find any similar postings about this. I'm looking into it myself too, and I'll keep this updated if I find something. I'm sure I can't be the only one! – Brian May 15 '16 at 08:03
0

They should be received in the order that they are sent. Make sure you're actually sending them in order and not calling an async function 4 times (and send order isn't guaranteed). (I read that you tested it but in all my testing I've never seen a receive come out of order if the send order was guaranteed.)

pschang
  • 2,568
  • 3
  • 28
  • 23
  • Thanks for the input. I just edited my post to include my code for the simple queuing functionality I added. Could you take a look at let me know if I'm doing something differently than you are? Thanks again! – Brian May 19 '16 at 23:24
0

I added a messageId counter to the app that resets to 0 on every start of messagehandling. Then I delay with that number * 100 ms. This way I can add intentional delays as well with code like messageDelay += 15

receivedMessage(event) {
  messageDelay = 0;
  //...

sendMessage extend:

function sendTextMessage(recipientId, messageText) {
//...
  setTimeout(function() {
    callSendAPI(messageData);
  }, messageDelay++ * 100)    
}
csomakk
  • 5,369
  • 1
  • 29
  • 34
0

The message is not sending in order because, the request is sent asynchronously to facebook, and can be sent in any order.

To solve this you have to call the next sendTextMessage when the message that should be sent before it has received a response.

Kayslay
  • 111
  • 5
0

Based on the recursive solution proposed by @user3884594, I kind of make it work using this (I removed the error handling in order to simplify):

send_messages (["message 01", "message 02", "message 03"]);

function send_messages (which, i = 0)
{
    request({
        url: 'https://graph.facebook.com/v2.10/me/messages',
        qs: { access_token: FACEBOOK_ACCESS_TOKEN },
        method: 'POST',
        json: { recipient: { id: senderId }, message: { text: which [i] }
    }, (error, response, body) => 
    {
        // You need to put your error handling logic here
        if (i++ < which.length - 1)
            send_messages (which, i);
    });
}
0

I had exactly same problem, that solution worked for me:

function sendMessage(recipient, messages, accessToken, i) {


    axios.post(baseURL + 'v2.11/me/messages/?access_token=' + accessToken,
        Object.assign({}, {
            messaging_type: "RESPONSE",
            recipient: {
                id: recipient
            }
        }, messages[i]['payload']) )
        .then(response => {

            if(i < messages.length) sendMessage( recipient, messages, accessToken, i+1 );

            },
            error => {})
        .catch(error => {});

}
sendMessage(recipient, flow['messages'], flow['page']['accessToken'], 0);

That's my question: Sequential Message Sending Using Facebook Send-API

K. Kuksin
  • 41
  • 9
-1

You can try putting them inside a setTimeout function so each one goes after a certain period of time.

So replace this:

sendTextMessage(user, "Hello!");
sendTextMessage(user, "1");
sendTextMessage(user, "2");
sendTextMessage(user, "3");

With this:

sendTextMessage(user, "Hello!");              

// 1 second

setTimeout(function() {
    sendTextMessage(user, "1");
}, 1000)

// 2 seconds

setTimeout(function() {
    sendTextMessage(user, "2");
}, 2000)

// 3 seconds

setTimeout(function() {
    sendTextMessage(user, "3");
}, 3000)    

And they should go one after another. You could also embed the functions inside each other if need be.

Eric Walier
  • 331
  • 2
  • 18
  • 3
    Unfortunately, I need a more "scalable" solution. I hoping there's something in the Messenger API that I'm just not using correctly but the docs seem pretty sparse on any details other than what I'm using shown above. – Brian May 14 '16 at 04:42
  • I've tried doing this, it is not really that reliable and there is an extreme delay in some messages so you couldn't still get them sequential 100% of the time. A more efficient and scalable solution like callbacks would be great, if FB can implement it. Although, I notice this chatbot can do it at ease: https://www.messenger.com/t/chatbotsmagazine So I'm wondering how they implemented it. – Carmela Mar 07 '17 at 03:41