Brian
Brian

Reputation: 8095

Facebook Messenger bot not sending messages in order

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)

Upvotes: 15

Views: 11039

Answers (11)

Akshay Bande
Akshay Bande

Reputation: 2587

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');
    })
  })
})

Upvotes: 1

K. Kuksin
K. Kuksin

Reputation: 51

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

Upvotes: 0

Emiliano Gonzalez
Emiliano Gonzalez

Reputation: 1

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);
    });
}

Upvotes: 0

Kayslay
Kayslay

Reputation: 111

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.

Upvotes: 0

csomakk
csomakk

Reputation: 5497

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)    
}

Upvotes: 0

ninjadave
ninjadave

Reputation: 46

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);
            }
        );    
    });
};

Upvotes: 1

Louise
Louise

Reputation: 151

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

Upvotes: 10

younglion
younglion

Reputation: 190

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.

Upvotes: 4

pschang
pschang

Reputation: 2618

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.)

Upvotes: 0

Corn Doggo
Corn Doggo

Reputation: 66

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.

Upvotes: 1

Eric Walier
Eric Walier

Reputation: 331

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.

Upvotes: -1

Related Questions