Skip to content
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

fix: add option to reconnect if connack has an error code #1948

Merged
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ the final connection when it drops.
The default value is 1000 ms which means it will try to reconnect 1 second
after losing the connection.

Note that this will only enable reconnects after either a connection timeout, or
after a successful connection. It will _not_ (by default) enable retrying
connections that are actively denied with a CONNACK error by the server.

To also enable automatic reconnects for CONNACK errors, set
`reconnectOnConnackError: true`.

<a name="topicalias"></a>

## About Topic Alias Management
Expand Down Expand Up @@ -415,6 +422,8 @@ The arguments are:
offline
- `reconnectPeriod`: `1000` milliseconds, interval between two
reconnections. Disable auto reconnect by setting to `0`.
- `reconnectOnConnackError`: `false`, whether to also reconnect if a CONNACK
is received with an error.
- `connectTimeout`: `30 * 1000` milliseconds, time to wait before a
CONNACK is received
- `username`: the username required by your broker, if any
Expand Down
6 changes: 6 additions & 0 deletions src/lib/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ export interface IClientOptions extends ISecureClientOptions {
* 1000 milliseconds, interval between two reconnections
*/
reconnectPeriod?: number
/**
* Set to true to enable the reconnect period to apply if the initial
* connection is denied with an error in the CONNACK packet, such as with an
* authentication error.
*/
reconnectOnConnackError?: boolean
/**
* 30 * 1000 milliseconds, time to wait before a CONNACK is received
*/
Expand Down
3 changes: 3 additions & 0 deletions src/lib/handlers/connack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ const handleConnack: PacketHandler = (client, packet: IConnackPacket) => {
rc,
)
client.emit('error', err)
if (client.options.reconnectOnConnackError) {
client['_cleanUp'](true)
}
}
}

Expand Down
35 changes: 35 additions & 0 deletions test/abstract_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3335,6 +3335,41 @@ export default function abstractTest(server, config, ports) {
})
})

it.skip('should reconnect on connack error if requested', function _test(t, done) {
let connackErrors = 0
const rcNotAuthorized = 135
const server2 = serverBuilder(config.protocol, (serverClient) => {
serverClient.on('connect', () => {
const rc = connackErrors === 0 ? rcNotAuthorized : 0
const connack =
version === 5 ? { reasonCode: rc } : { returnCode: rc }
serverClient.connack(connack)
})
})
mgabeler-lee-6rs marked this conversation as resolved.
Show resolved Hide resolved
server2.listen(ports.PORTAND50, () => {
const client = connect({
host: 'localhost',
port: ports.PORTAND50,
reconnectPeriod: 10,
reconnectOnConnackError: true,
})
.on('error', (err) => {
assert.instanceOf(err, ErrorWithReasonCode)
assert.equal(
(err as ErrorWithReasonCode).code,
rcNotAuthorized,
)
assert.equal(connackErrors, 0)
connackErrors++
})
.on('connect', () => {
assert.equal(connackErrors, 1)
client.end(true, done)
server2.close()
})
})
})

it(
'should resend in-flight QoS 1 publish messages from the client',
{
Expand Down
Loading