Бот Facebook Messenger не отправляет сообщения по порядку

Я экспериментирую с созданием простого чат-бота Facebook Messenger, и у меня возникают проблемы с последовательной отправкой сообщений.

введите описание изображения здесь

В приведенном выше примере он должен был напечатать по порядку «Hello!», «1», «2», «3». В настоящее время я слежу за документами Facebook, найденными здесь, чтобы реализовать эту простую функцию текстового сообщения. Я включил свой код сервера Express Node.JS ниже:

Определение функции sendTextMessage():

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

Используя его для отправки ответа:

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

Я даже пробовал реализовать простую очередь, которая ставит сообщения в очередь и отправляет только одно сообщение за раз после каждого успешного обратного вызова request. Это заставляет меня подозревать, что я неправильно взаимодействую с Messenger API.

Кто-нибудь сталкивался с этой проблемой? Как я могу получить сообщения для последовательной отправки? Спасибо!

ИЗМЕНИТЬ

Поскольку я реализовал простую очередь, но все еще испытываю эту проблему, я включаю сюда код для своей простой системы очередей.

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 */);

ОБНОВЛЕНИЕ

Об этой «ошибке» сообщили в Facebook, но похоже, что они не собираются ее исправлять. Пожалуйста, прочтите ветку тикетов в сообщении Facebook здесь, чтобы узнать, что они говорят о происходящем. (Спасибо Луизе за то, что привлекла к этому внимание Facebook)


person Brian    schedule 11.05.2016    source источник
comment
@brain ты нашел какое-нибудь решение?   -  person Nagaraju    schedule 25.07.2016
comment
@Raju Я еще не нашел явного решения, но если вы посмотрите ниже, кто-то отправил отчет об ошибке, и я считаю, что над этим работают. Мне удалось обойти это, реализовав произвольную 1-секундную задержку между отправкой сообщений, рекурсивно используя setTimeout в очереди сообщений. Работает, но вроде как взлом. Надеюсь, это поможет!   -  person Brian    schedule 25.07.2016
comment
Мы решили это с помощью этого npmjs.com/package/fibers   -  person Nagaraju    schedule 27.07.2016
comment
Спасибо за код очереди! Это простое маленькое решение :)   -  person Tony Anziano    schedule 13.10.2016
comment
Я только что реализовал систему очередей, которая, кажется, решает эту проблему, и сделал это аналогичным образом.   -  person Alex McCabe    schedule 01.02.2017
comment
Вы пытались отправить 200 ответов в течение 15 секунд? Я видел это, в котором упоминается та же проблема.   -  person Stephen Tetreault    schedule 20.02.2017
comment
Нет, не знал, но это может быть потенциальный подход. В настоящее время я больше не работаю над этим проектом, но эта ветка, похоже, продолжает получать просмотры, поэтому, надеюсь, другие люди, наткнувшиеся на это, сочтут это полезным.   -  person Brian    schedule 23.02.2017
comment
это было исправлено?   -  person Rohan Sood    schedule 21.06.2017
comment
@RohanSood Я больше не работаю над этим проектом, поэтому больше не слежу за ним. Последнее, что я знаю об этой проблеме, это то, что кто-то создал отчет об ошибке для разработчиков Facebook, и они ответили, что это не проблема и не будет исправлена: developers.facebook.com/bugs/565416400306038. Тема на веб-сайте разработчика Facebook должна быть в состоянии предложить вам дополнительную помощь в отношении официального ответа Facebook. Надеюсь это ответит на твой вопрос!   -  person Brian    schedule 21.06.2017
comment
это происходит из-за природы nodejs. Если вы используете node.js и отправляете несколько сообщений с обратными вызовами, очень вероятно, что он получит случайный порядок, поскольку это происходит асинхронно.   -  person Nyi Nyi    schedule 12.10.2018


Ответы (11)


Я отправил отчет об этой ошибке в Facebook, потому что у меня была та же проблема. Они признали, что это действительно ошибка, и работают над ее исправлением: https://developers.facebook.com/bugs/565416400306038

person Louise    schedule 22.06.2016
comment
Спасибо за сообщение об этой ошибке в Facebook, надеюсь, они это исправят! - person Brian; 28.06.2016

После того, как вы отправите POST на / me / messages, вы получите ответ с идентификатором сообщения (у меня начинается с 'mid.', Что, возможно, означает идентификатор сообщения?):

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

После того, как API-интерфейс FB Messenger полностью получит, вы получите вызов на свой веб-перехватчик (без событий сообщений), который подтверждает получение:

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

Я думаю, что квитанция о доставке - лучший способ обеспечить доставку, а затем отправить следующее сообщение.

person younglion    schedule 27.05.2016
comment
Моя ошибка, согласно новым заметкам разработчика Facebook, квитанции о доставке не гарантируются, и хотя это может хорошо работать для некоторых сред разработки, этот метод на самом деле не будет хорошим подходом в продукте. В настоящее время мы внедряем задержку, хотя должен быть какой-то лучший способ справиться с этим, даже в масштабе. - person younglion; 29.07.2016

Вместо добавления статических таймаутов я бы создал структуру данных очереди. Когда бот хочет отправить сообщение, добавьте его содержимое в конец очереди. В обратном вызове публикации сообщения проверьте, есть ли еще какие-либо сообщения в очереди, снова вызовите функцию, используя рекурсию, и удалите из очереди соответственно.

person Corn Doggo    schedule 14.05.2016
comment
Как я упоминал в конце своего сообщения, я попытался реализовать очередь, в которой я рекурсивно отправлял сообщения в очереди, которые после каждого успешного обратного вызова отправки. На удивление это все еще не сработало. - person Brian; 14.05.2016
comment
@Brian - это бот и принимающая сторона в одной сети? Возможно, получение происходит настолько мгновенно, что порядок сообщений при загрузке нарушается. - person Corn Doggo; 14.05.2016
comment
Я использую messenger.com в качестве клиента, где я взаимодействую с ботом. Сам бот работает как приложение Node.js на серверах Heroku. - person Brian; 15.05.2016
comment
@Brian: Мне нужно было бы изучить это, но я предполагаю, что бэкэнд мессенджера на самом деле тоже асинхронный и не зависит от времени отправки, а скорее от времени, когда бэкэнд распределяет их принимающей стороне, поэтому он будет ненадежно отправлять их даже в формате очереди. Возможно, вы могли бы попробовать систему очереди и добавить произвольную задержку перед обработкой следующего в очереди? По крайней мере, это даст бэкэнду небольшой буфер для обработки запроса. Вы также можете решить отправить следующий, основываясь на сроках доставки, но это не имеет отношения ... - person Corn Doggo; 15.05.2016
comment
Спасибо, Чейз, я удивлен, что не смог найти никаких похожих сообщений об этом. Я тоже в этом разбираюсь и буду держать в курсе, если что-нибудь найду. Я уверен, что не могу быть единственным! - person Brian; 15.05.2016

Реализуйте запрос на отправку как обещание и отправляйте последующие сообщения только после разрешения предыдущего.

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);
            }
        );    
    });
};
person ninjadave    schedule 10.04.2017

Вы можете достичь QUEUING обещаниями.

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

person Akshay Bande    schedule 20.12.2019
comment
Спасибо за это - person paul-schultz; 03.01.2021

Их следует получать в том порядке, в котором они были отправлены. Убедитесь, что вы действительно отправляете их по порядку, а не вызываете асинхронную функцию 4 раза (и порядок отправки не гарантируется). (Я читал, что вы его тестировали, но за все время тестирования я ни разу не видел, чтобы получение выходило из строя, если порядок отправки был гарантирован.)

person pschang    schedule 17.05.2016
comment
Спасибо за вклад. Я только что отредактировал свое сообщение, включив в него свой код для простой функции очереди, которую я добавил. Не могли бы вы взглянуть на дайте мне знать, если я делаю что-то не так, как вы? Еще раз спасибо! - person Brian; 20.05.2016

Я добавил в приложение счетчик messageId, который сбрасывается до 0 при каждом запуске обработки сообщений. Затем я задерживаю это число * 100 мс. Таким образом, я могу добавить преднамеренные задержки с помощью кода типа messageDelay += 15

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

sendMessage расширить:

function sendTextMessage(recipientId, messageText) {
//...
  setTimeout(function() {
    callSendAPI(messageData);
  }, messageDelay++ * 100)    
}
person csomakk    schedule 17.06.2017

Сообщение отправляется не по порядку, потому что запрос асинхронно отправляется в facebook и может быть отправлен в любом порядке.

Чтобы решить эту проблему, вы должны вызвать следующий sendTextMessage, когда сообщение, которое должно быть отправлено, прежде чем оно получит ответ.

person Kayslay    schedule 17.06.2017

Основываясь на рекурсивном решении, предложенном @ user3884594, я как бы заставляю его работать, используя это (я удалил обработку ошибок, чтобы упростить):

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);
    });
}
person Emiliano Gonzalez    schedule 21.09.2017

У меня была точно такая же проблема, это решение сработало для меня:

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

Это мой вопрос: Последовательная отправка сообщений с использованием Facebook Send-API

person K. Kuksin    schedule 20.01.2018

Вы можете попробовать поместить их в функцию setTimeout, чтобы каждая из них выполнялась через определенный период времени.

Так что замените это:

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

С этим:

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)    

И они должны идти один за другим. При необходимости вы также можете встроить функции друг в друга.

person Eric Walier    schedule 14.05.2016
comment
К сожалению, мне нужно более масштабируемое решение. Я надеюсь, что в Messenger API есть что-то, что я использую неправильно, но документы кажутся довольно скудными по любым деталям, кроме того, что я использую, показанного выше. - person Brian; 14.05.2016
comment
Я пробовал сделать это, это не совсем надежно, и в некоторых сообщениях очень большая задержка, поэтому вы все равно не можете получать их последовательно в 100% случаев. Было бы здорово, если бы FB реализовал более эффективное и масштабируемое решение, такое как обратные вызовы. Хотя я заметил, что этот чат-бот может делать это легко: messenger.com/t/chatbotsmagazine Итак Интересно, как они это реализовали. - person Carmela; 07.03.2017