如何在Node.js重新连接后正确检查RabbitMQ通道是否已打开?

时间:2016-02-12 18:13:23

标签: node.js rabbitmq amqp

我正在使用amqplib我试图实现重新连接机制。但是,重新建立连接后,看起来我的频道仍然关闭。我该如何解决这个问题?这是我的代码。

var pubQueue = [];
module.exports = {
  connect: function (callback) {
    var self = this;
    amqp.connect(config.queue.url, function(err, connection) {
      if (err) {
        console.error("[AMQP]", err.message);
        return setTimeout(module.exports.connect, 2000);
      }

      connection.on("error", function(err) {
        if (err.message !== "Connection closing") {
          console.error("[AMQP] conn error", err.message);
        }
      });

      connection.on("close", function() {
        console.error("[AMQP] reconnecting");
        return setTimeout(module.exports.connect, 2000);
      });

      connection.createChannel(function(err, ch) {
        console.log('connection is reestablished');
        self.channel = ch;
        return callback ? callback() : false;
      });
    });
  },

  publish: function (message, callback) {
    var self = this;
    var key = this.generateKey(message);
    var m = new Buffer(JSON.stringify(message));

    try {
      self.channel.assertExchange(config.queue.exchange, 'topic', {durable: false, nowait: true});
      self.channel.publish(config.queue.exchange, key, m, {nowait: true});
      return callback ? callback() : true;
    } catch(err) {
      pubQueue.push({key: key, m: m});
      console.log(err);
    }
  }
} 
一旦快速应用程序启动,将调用

connect()。但是publish会在每次请求时调用。这就是我pubQueue存储丢失邮件的原因。我还没有实现重新发送队列中的消息的功能,但我先得到了这个错误,我似乎无法绕过它。

connection is reestablished
{ [IllegalOperationError: Channel closed]
  message: 'Channel closed',
  stack: 'IllegalOperationError: Channel closed\n    at Channel.}

1 个答案:

答案 0 :(得分:0)

当连接关闭时,将 self.channel 设置为 null 并且在 publish() 中,如果 self.channel 为 null,则返回而不做任何事情(可能有更好的方法,但这证明了该能力)。

>

顺便说一下,由于 connect 需要回调参数,将 setTimeout 包裹在 Promise 中并使用 then() 使用回调参数调用连接函数,如下所示:

new Promise((resolve) => {
  setTimeout(resolve, 2000);
}).then(() => {
  module.exports.connect(callback);
});

所以修改后的代码,在没有运行 RabbitMQ 的情况下启动时,会反复尝试连接,直到 RabbitMQ 启动。它开始重复发布,如果 RabbitMQ 停止,它会优雅地尝试重新连接并停止发布。

工作代码由我用于测试的服务器 s.js 组成,该服务器连接并重复调用发布:

const amqp = require("./so.js");

const doPublish = () => {
  amqp.publish("test", () => {
    console.log("publish complete");
  });
  // publish again
  setTimeout(doPublish, 2000);
};

amqp.connect(function () {
  doPublish();
})

您的代码修订版 so.js 如下:

var config = {
  queue: {
    url: "amqp://localhost/",
    exchange: 'so_exchange',
  },
};

var amqp = require("amqplib/callback_api");

var pubQueue = [];

module.exports = {

  reconnect: function (callback) {
    new Promise((resolve) => {
      setTimeout(resolve, 2000);
    }).then(() => {
      module.exports.connect(callback);
    });
  },

  connect: function (callback) {
    var self = this;
    amqp.connect(config.queue.url, function (err, connection) {
      if (err) {
        console.error("[AMQP]", err.message);
        return module.exports.reconnect(callback);
      }

      connection.on("error", function (err) {
        if (err.message !== "Connection closing") {
          console.error("[AMQP] conn error", err.message);
        }
      });

      connection.on("close", function () {
        console.error("[AMQP] reconnecting");
        self.channel = null;
        return module.exports.reconnect(callback);
      });

      connection.createChannel(function (err, ch) {
        console.log("connection is reestablished");
        self.channel = ch;
        return callback();
      });
    });
  },

  publish: function (message, callback) {
    var self = this;
    var key = 'test'; //this.generateKey(message);
    var m = Buffer.from(JSON.stringify(message));

    if (self.channel == null) return;

    try {
      self.channel.assertExchange(config.queue.exchange, "topic", {
        durable: false,
        nowait: true,
      });
      self.channel.publish(config.queue.exchange, key, m, { nowait: true });
      return callback();
    } catch (err) {
      pubQueue.push({ key: key, m: m });
      console.log(err);
    }
  },
};