我正在使用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.}
答案 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);
}
},
};