протокол AMQP.узел не обнаружит падение соединения

у нас есть узел.сценарий js работает с сокетом.сервер ввода-вывода, клиенты которого используют сообщения из очереди RabbitMQ. Недавно мы перешли на Amazon AWS, и RabbitMQ теперь представляет собой кластер из двух машин (избыточных экземпляров). Соединение AMQP время от времени теряется (это ограничение, которое поступает из среды высокой доступности с избыточными VMs, и мы должны справиться с этим), и если попытка повторного подключения сделана, DNS выбирает, к какому экземпляру подключиться (это кластер с репликация данных, поэтому не имеет значения, к какому экземпляру подключиться).

проблема в том, что попытка повторного подключения никогда не предпринимается; через некоторое время, когда соединение потеряно, amqp.узел, по-видимому, не замечает, что соединение было потеряно. Кроме того, потребители перестают получать сообщения и сокет.io server просто перестает принимать новые подключения.

у нас есть тайм-аут сердцебиения 55 секунд (не путать с сокетом.IO heartbeat timeout) установить на RabbitMQ URL и проверяют "ошибку" и "закрытие" событий с помощью amqp.API обратного вызова узла, но они, по-видимому, никогда не выдаются. Очереди ожидают, что потребленные сообщения будут ack'Ed. Мы хотим, чтобы сценарий узла обнаружил потерянное соединение и закончил себя, поэтому среда автоматически запустит новый процесс и снова установит соединение.

вот код, возможно, мы делаем что-то не так с amqp.API обратного вызова узла или что-то еще.

var express = require('express');
app = express();
var http = require('http');
var serverio = http.createServer(app);
var io = require('socket.io').listen(serverio, { log: false });
var socket;
var allcli = [];
var red, blue, green, magenta, reset;
red   = '3[31m';
blue  = '3[34m';
green  = '3[32m';
magenta  = '3[35m';
orange = '3[43m';
reset = '3[0m';

var queue = 'ha.atualizacao_mobile';
var urlRabbit = 'amqp://login:password@host?heartbeat=55' // Amazon
var amqp = require('amqplib/callback_api');
var debug = true;

console.log("Original Socket.IO heartbeat interval: " + io.get('heartbeat interval') + " seconds.");
io.set('heartbeat interval', 10 * 60);
console.log("Hearbeat interval changed to " + io.get('heartbeat interval') + " seconds to reduce battery consumption in the mobile clients.");

console.log("Original Socket.IO heartbeat timeout: " + io.get('heartbeat timeout') + " seconds.");
io.set('heartbeat timeout', 11 * 60);
console.log("Heartbeat timeout set to " + io.get('heartbeat timeout') + " seconds.");


io.sockets.on('connection', function(socket){

    socket.on('error', function (exc) {
        console.log(orange+"Ignoring exception: " + exc + reset);
    });

    socket.on('send-indice', function (data) {
        // Some business logic
    });

    socket.on('disconnect', function () {
        // Some business logic
    });

}); 

function updatecli(data){
    // Some business logic
}

amqp.connect(urlRabbit, null, function(err, conn) {
    if (err !== null) {
        return console.log("Error creating connection: " + err);
    }

    conn.on('error', function(err) {
        console.log("Generated event 'error': " + err);
    });

    conn.on('close', function() {
        console.log("Connection closed.");
        process.exit();
    });

    processRabbitConnection(conn, function() {
        conn.close();
    });
});

function processRabbitConnection(conn, finalize) {
    conn.createChannel(function(err, channel) {

        if (err != null) {
            console.log("Error creating channel: " + err);
            return finalize();
        }

        channel.assertQueue(queue, null, function(err, ok) {
            if (err !== null) {
                    console.log("Error asserting queue " + queue + ": " + err);
                    return finalize();
            }

            channel.consume(queue, function (msg) {
                if (msg !== null) {
                    try {
                        var dataObj = JSON.parse(msg.content);
                        if (debug == true) {
                            //console.log(dataObj);
                        }
                        updatecli(dataObj);
                    } catch(err) {
                        console.log("Error in JSON: " + err);
                    }
                    channel.ack(msg);
                }
            }, null, function(err, ok) {
                if (err !== null) {
                    console.log("Error consuming message: " + err);
                    return finalize();
                }
            });
        });
    });
}

serverio.listen(9128, function () {
  console.log('Server: Socket IO Online  - Port: 9128 - ' + new Date());
});

1 ответов


по-видимому, проблема решена. Проблема заключалась в почти 60 секундах сердцебиения. Он конфликтует с балансировщиком нагрузки RabbitMQ, который проверяет каждые 1 минуту или около того, прошли ли данные через соединение или нет (если данные не прошли, он разрывает соединение). Соединение AMQP перестает получать сообщения, и библиотека, по-видимому, не реагирует на это. Более низкое сердцебиение (например, 30 секунд) необходимо для того, чтобы избежать этой ситуации.