Skip to content

how to send messages in order? #192

Description

@wizzard0

when using e.g. C# Telegram.Bot library, I can do successive calls to bot.sendmessage and the user receives them in the order which I used to send. With node-telegram-bot-api, I often get replies in random order.

Repro: create a basic echo bot, verify it works, stop bot, send 3-4 messages, start bot, see messages received by bot in order, but replies in chat in random order.

Activity

  1. alexandercerutti commented on Sep 26, 2016

    @alexandercerutti
    Contributor

    if I understood rightly you problem, receiving replies in various order, happens due to bot.sendMessage asyncronicity.

    You can use Promise's .then() method. It accepts only one parameter: a callback with a(n optional) parameter that will contain last sent message details, like message_id.

    So you can do:

    bot.sendMessage(...).then(() => {
        bot.sendMessage(...);
    });

    Chaining such this way messages is a bad way, but the only one Imho.

  2. GochoMugo commented on Sep 26, 2016

    @GochoMugo
    Collaborator

    I am in support of @alexandercerutti's answer.

    first approach:

    Furthermore, here is another approach you can use to send multiple messages:

    var Promise = require('bluebird');
    
    function sendMessages(bot, chatId, messages) {
        return Promise.mapSeries(messages, function(message) {
            return bot.sendMessage(chatId, message);
        });
    }
    
    // example usage
    sendMessages(bot, chatId, ["first", "second", "third"])
        .then(function() {
            console.log("All messages sent, in series!");
        });

    However, the above approach assumes you have the messages prepared in advance.

    second approach:

    For the use case where you are invoking bot.sendMessage() arbitrarily, you might want to implement it using a queue of messages:

    var Promise = require('bluebird');
    var queue = [];
    var inUseQueue = [];
    
    function _sendMessages() {
        // if we are already sending messages from the queue, or
        // the queue is empty, stop
        if (inUseQueue.length || !queue.length) return;
    
        console.log("processing queue");
        inUseQueue = queue;
        queue = [];
        Promise.mapSeries(inUseQueue, function(request) {
            var resolve = request.resolve;
            var reject = request.reject;
            var bot = request.bot;
            console.log("sending message '%s'", request.message);
            return bot.sendMessage(request.chatId, request.message)
                .then(resolve)
                .catch(reject);
        }).then(function() {
            console.log("queue processed");
            inUseQueue = [];
            _sendMessages();
        });
    }
    
    function sendMessage(bot, chatId, message) {
        var resolve, reject;
        var promise = new Promise(function(promiseResolve, promiseReject) {
            resolve = promiseResolve;
            reject = promiseReject;
        });
        console.log("pushing message '%s' to queue", message);
        queue.push({ bot, chatId, message, resolve, reject });
        process.nextTick(_sendMessages);
        return promise;
    }
    
    // example usage
    function toLog(message) { return function() { console.log(message); }; };
    
    sendMessage(bot, chatId, "first").then(toLog("first sent!"));
    
    setTimeout(function() {
        sendMessage(bot, chatId, "second").then(toLog("second sent!"));
    }, 1000);
    
    setTimeout(function() {
        sendMessage(bot, chatId, "third").then(toLog("third sent!"));
    }, 2000);

    The above example usage gave me this output:

    pushing message 'first' to queue
    processing queue
    sending message 'first'
    pushing message 'second' to queue
    pushing message 'third' to queue
    first sent!
    queue processed
    processing queue
    sending message 'second'
    second sent!
    sending message 'third'
    third sent!
    queue processed
    

    Hope that gives you an idea of how to solve your problem.

    (And maybe a PR for this could be awesome!)

  3. wizzard0 commented on Sep 26, 2016

    @wizzard0
    Author

    oh well. I guess I'll make generic per-user "dispatch queue" where I'd put the messages and it would ensure it wont interleave them... or aggregate, if I accidentally spam it with 100 msgs :)

    Thanks for the advice though.

    UPD: nice, you added the queue example while I was writing my comment :)

  4. wizzard0 commented on Sep 26, 2016

    @wizzard0
    Author

    (And maybe a PR for this could be awesome!)

    @GochoMugo btw, I noticed we have a fork (node-telegram-bot-api-latest), shall I switch to it and submit PRs there, if any?

  5. GochoMugo commented on Sep 26, 2016

    @GochoMugo
    Collaborator

    @wizzardo That repo is mainly for merging PRs from this repo. It is just bleeding-edge for kinda-advanced users (and might disappear, if @yagop keeps up with PRs here). Also see the beginning of the README in the fork.

    So, please draft your PRs against this repo. I will (most probably) help you perfect it here, then we will have our bot automatically draft it from here to the fork and we merge.

  6. wizzard0 commented on Sep 26, 2016

    @wizzard0
    Author

    hmmm... given there was a few months since last PR was merged, maybe it's possible to ask @yagop for commit access?

  7. GochoMugo commented on Sep 26, 2016

    @GochoMugo
    Collaborator

    I might do that some time to come, but I gave him the benefit of doubt: we get busy at times, you know! But I might query him and see the result.

  8. GochoMugo commented on Oct 26, 2016

    @GochoMugo
    Collaborator

    I have built a wrapper around this library to add higher-level features. Currently, it supports sending messages in order. It is called tgfancy. See https://github.com/GochoMugo/tgfancy for more information.

  9. GochoMugo commented on Oct 26, 2016

    @GochoMugo
    Collaborator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions