我有一个在 websockets 上运行并部署到 Cloud Run 的 Node JS MQTT 服务器。此服务器使用 Aedes MQTT 代理库 ( https://github.com/moscajs/aedes )。客户端通过端口 443 连接到该服务器。一切正常,但每个客户端都会定期与 MQTT 代理断开连接(大约每 5 分钟,因为每个客户端首次连接)当服务器部署到专用机器或Google Cloud VM,仅在部署到 Google Cloud Run 时发生。
为了说明这个问题,我在 NodeJS 中编写了一个超级简单的 MQTT 服务器,它允许任何客户端连接并回显到队列“响应”客户端发送到队列“消息”的任何消息和一个 NodeJS 脚本来测试它。您可以在https://github.com/madomingo/mqtt_test/tree/main中找到完整的 2 文件项目
服务器代码是:
const aedes = require('aedes')()
const ws = require('websocket-stream')
const port = 8882
const WEB_SOCKETS = true
let httpServer
if (WEB_SOCKETS) {
httpServer = require('http').createServer()
ws.createServer({ server: httpServer }, aedes.handle)
} else {
httpServer = require('net').createServer(aedes.handle)
}
httpServer.listen(port, function () {
let type = (WEB_SOCKETS) ? "WebSockets" : "HTTP"
console.log('STARTED: ' + type + ' server listening on port ', port)
})
aedes.subscribe('messages', function (packet, callback) {
let msg = packet.payload.toString()
console.log('Received message', msg);
aedes.publish(
{
topic: 'responses',
payload: msg,
retain: false
}
);
});
我还有一个 NodeJS 测试脚本,它连接到服务器并每 15 秒将日期时间发送到队列:
let mqtt = require('mqtt');
// Web sockets host
const host = "ws://localhost:8882"
let clientId = 'test web client ' + Date.now
let client = mqtt.connect(host, {
clientId: clientId
});
client.on('connect', function () {
console.log("Connected to server")
client.subscribe('responses');
sendMessage()
setInterval(() => {
sendMessage()
}, 15000);
})
client.on('message', function (topic, message) {
console.log('Received a message in topic: ' + topic + ": " + message.toString());
});
client.on('error', function(e) {
console.log('Received an error: ' + e.message)
})
client.on('disconnect', function() {
console.log('Client was disconnected ' )
})
client.on('reconnect', function() {
console.log('Client was reconnected ')
})
client.on('close', function() {
console.log('Client was closed ' )
})
client.on('offline', function() {
console.log('Client was offline ')
})
function sendMessage() {
let now = new Date().toISOString()
let msg = "Current time = " + now
console.log("Publishing data", msg)
client.publish('messages', msg);
}
如果我在本地运行服务器和测试脚本,一切都按预期工作:每 15 秒,客户端将日期时间发送到队列“消息”中的服务器,然后服务器立即回显这个日期时间到队列“响应”。服务器和客户端都登录到控制台。这无限期地运行并且没有断开连接。
我发现的问题是当服务器部署到 Google Cloud Run 服务时(我已经这样做了,我得到了 url:test-mqtt-server-kdtisjwi5a-ew.a.run.app)。
在测试脚本中,我将主机 url 更改为:const host = "wss://test-mqtt-server-kdtisjwi5a-ew.a.run.app:443"。然后再次运行测试脚本,客户端连接到部署到 Cloud Run 的服务器,一段时间后,控制台按预期显示日志:
Connected to server
Publishing data Current time = 2021-09-16T16:06:26.937Z
Received a message in topic: responses: Current time = 2021-09-16T16:06:26.937Z
Publishing data Current time = 2021-09-16T16:06:41.944Z
Received a message in topic: responses: Current time = 2021-09-16T16:06:41.944Z
但是在第一次连接后每隔 5 分钟,客户端会意外断开连接,尽管它会立即重新连接。日志现在显示:
Received a message in topic: responses: Current time = 2021-09-16T16:11:11.975Z
Client was offline
Client was closed
Client was reconnected
Connected to server
Publishing data Current time = 2021-09-16T16:11:28.121Z
Received a message in topic: responses: Current time = 2021-09-16T16:11:28.121Z
我没想到会断开连接,因为显然没有任何连接问题。所以我的问题是,为什么在部署到 Cloud Run 时会出现这种断开连接?并且可以避免吗?
任何帮助表示赞赏,谢谢!