-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug]: wrong connection string with a port puts mqtt client into an endless loop #1824
Comments
@maximivanov Just to know, is this a regression or was it failing also with older versions? |
@robertsLando I never tried connecting to a hostname with port while on a previous version so not sure if the issue exists in versions before 5.4.0. However there was a similar problem that was fixed somewhere in between 5.0.3 and 5.4.0: Trying to connect to a mqtts://wrong-host-without-port timed out correctly. Hope it helps. |
Wait but you have set a reconnect period of 1 second and I don't see any error here as it exactly retries after 1 second that the connection is closed:
So this is correct. You should pass |
@robertsLando thanks for getting back with the recommendation. I'm a bit confused though - why does it consider it a reconnect if it never connected in the first place (remember the host in the example above is made up and is wrong). Why do I see a connect timeout if I remove the port from that exact connection string? I would like to have the reconnect functionality (the app is a long running process) but only once we know the initial connection was successful - is there a way to do this? |
This is not possible and changing the bahaviour of this would be breaking: what if for any reason your broker is down or your internet connection is not working well on client on first try? It would just give up thinking that the broker is unreachable but that's wrong. The alternative is to put this under a configuration option but I really don't think it's so much useful I think your best choice, if you really want this, is to try pinging the server to see if it's up or not before connecting to MQTT broker |
@robertsLando does having a configuration option to specify the maximum number of reconnect attempts make sense? My main concern is right now the only options are:
If there was a way to make it throw after N unsuccessful connection attempts that would help address the issue: try {
const mqttClient = await mqtt.connectAsync(url, {
reconnectPeriod: 1000,
maxReconnectAttempts: 10,
});
} catch (error) {
// ... 11 seconds later
// error is "Reached max number of reconnect attempts (10)"
} |
Yeah it could make sense, feel free to submit a PR and remember to add a test for that |
Having trouble with the workarounds suggested above.
const mqtt = require('mqtt');
// this is a non existent hostname and it's part of the test
const url = 'mqtt://a7dc229b79e0425222318eb495f0dddd.s1.eu.hivemq.cloud:8883';
async function main() {
console.log(new Date());
await new Promise((resolve) => { setTimeout(resolve, 1000); });
console.log(new Date());
const mqttClient = await mqtt.connectAsync(url, {
connectTimeout: 5000,
username: 'does not matter',
password: 'does not matter',
reconnectPeriod: 0,
});
console.log(new Date());
await new Promise((resolve) => { setTimeout(resolve, 1000); });
console.log(new Date());
await mqttClient.endAsync();
}
main(); Run the script: ~/src/local/mqtt-wrong-host-infinite-connection-loop 18:48:47
❯ DEBUG='mqttjs*' node main.js
2024-04-10T17:49:04.834Z
2024-04-10T17:49:05.842Z
mqttjs connecting to an MQTT broker... +0ms
mqttjs:client MqttClient :: version: undefined +0ms
mqttjs:client MqttClient :: environment node +0ms
mqttjs:client MqttClient :: options.protocol mqtt +1ms
mqttjs:client MqttClient :: options.protocolVersion 4 +0ms
mqttjs:client MqttClient :: options.username does not matter +0ms
mqttjs:client MqttClient :: options.keepalive 60 +0ms
mqttjs:client MqttClient :: options.reconnectPeriod 0 +0ms
mqttjs:client MqttClient :: options.rejectUnauthorized undefined +0ms
mqttjs:client MqttClient :: options.properties.topicAliasMaximum undefined +0ms
mqttjs:client MqttClient :: clientId mqttjs_12961e0b +0ms
mqttjs:client MqttClient :: setting up stream +0ms
mqttjs:client connect :: calling method to clear reconnect +1ms
mqttjs:client _clearReconnect : clearing reconnect timer +0ms
mqttjs:client connect :: using streamBuilder provided to client to create stream +0ms
mqttjs calling streambuilder for mqtt +4ms
mqttjs:tcp port 8883 and host a7dc229b79e0425222318eb495f0dddd.s1.eu.hivemq.cloud +0ms
mqttjs:client connect :: pipe stream to writable stream +8ms
mqttjs:client connect: sending packet `connect` +1ms
mqttjs:client _writePacket :: packet: {
mqttjs:client cmd: 'connect',
mqttjs:client protocolId: 'MQTT',
mqttjs:client protocolVersion: 4,
mqttjs:client clean: true,
mqttjs:client clientId: 'mqttjs_12961e0b',
mqttjs:client keepalive: 60,
mqttjs:client username: 'does not matter',
mqttjs:client password: 'does not matter',
mqttjs:client properties: undefined
mqttjs:client } +0ms
mqttjs:client _writePacket :: emitting `packetsend` +1ms
mqttjs:client _writePacket :: writing to stream +0ms
mqttjs:client _writePacket :: writeToStream result true +19ms
mqttjs:client (mqttjs_12961e0b)stream :: on close +112ms
mqttjs:client _flushVolatile :: deleting volatile messages from the queue and setting their callbacks as error function +0ms
mqttjs:client stream: emit close to MqttClient +0ms
mqttjs:client close :: connected set to `false` +0ms
mqttjs:client close :: clearing connackTimer +0ms
mqttjs:client close :: clearing ping timer +0ms
mqttjs:client close :: calling _setupReconnect +0ms
mqttjs:client _setupReconnect :: doing nothing... +0ms
~/src/local/mqtt-wrong-host-infinite-connection-loop 18:49:06
❯ echo $?
0 As you can see the second pair of dates is never printed, yet the process exit code is 0. More generally should this issue be reopened? Having an async function (connectAsync, publishAsync) block indefinitely because of the external conditions (mqtt connection cannot be established, whatever) without a way to terminate it does not sound right. |
MQTT.js/src/lib/connect/index.ts Lines 187 to 191 in fc8fafb
Did you tried to reproduce the issue using mqtt connect (not async) and handle it your own?
Would you like to submit a PR? |
@robertsLando Regarding:
It seems the I believe simply adding a signature would to the trick. |
In most cases you still want retries to account for transient network errors so I looked at the code but unfortunately couldn't figure out how to add the retry count logic within reasonable time and had to move on. |
@maximivanov Just add an event listener to reconnect and stop when it reaches a specific number of retries? |
MQTTjs Version
5.4.0
Broker
Doesn't matter (testing connection to a wrong hostname)
Environment
NodeJS
Description
When trying to connect to a wrong URL that contains a port, the client never throws an error
Minimal Reproduction
Verify versions:
❯ node --version v20.9.0 ❯ npm --version 10.2.5 ❯ npm list | grep mqtt ├── mqtt@5.4.0
Add a script:
Run the script:
DEBUG='mqttjs*' node mqtt-connect-issue.mjs
Expected: process errors after 5 seconds because the hostname is not reachable.
Actual: process never exits.
Note: if you remove the port part (
:8883
) from the connection string, it will correctly time out and throw after 5 seconds.Debug logs
The text was updated successfully, but these errors were encountered: