Say in the options table that a proven link resets the backoff

maxDelay bounds the wait and sets the bar a link must clear, and only the
first was documented, so tuning it up quietly lengthened every recovery.

The unreadable PDU the tests write is one named constant now.
This commit is contained in:
2026-08-31 22:59:57 +02:00
parent 8e4d472f72
commit bfc85ee4dd
3 changed files with 6 additions and 6 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ Every one is optional.
| `shutdownTimeout` | `5000` | How long `close()` and `unbind()` wait for the requests this end already sent; `0` waits forever. | | `shutdownTimeout` | `5000` | How long `close()` and `unbind()` wait for the requests this end already sent; `0` waits forever. |
| `maxOutstanding` | `10` | Requests allowed on the wire at once; further sends queue. | | `maxOutstanding` | `10` | Requests allowed on the wire at once; further sends queue. |
| `smsIdFormat` | — | The notation the SMSC writes message ids in, per place it writes them: `{ receipt: 'decimal', submitResp: 'hex' }`. Only needed where the two disagree. | | `smsIdFormat` | — | The notation the SMSC writes message ids in, per place it writes them: `{ receipt: 'decimal', submitResp: 'hex' }`. Only needed where the two disagree. |
| `reconnect` | on | Re-binds after a drop, an idle timeout, or a stream the library cannot read, backing off from `minDelay` 1 s to `maxDelay` 30 s. `{ minDelay, maxDelay }` retunes it; `false` turns it off, so a drop ends the session. | | `reconnect` | on | Re-binds after a drop, an idle timeout, or a stream the library cannot read, backing off from `minDelay` 1 s to `maxDelay` 30 s and starting over at `minDelay` once a link has lasted `maxDelay`. `{ minDelay, maxDelay }` retunes it; `false` turns it off, so a drop ends the session. |
| `log` | silent | Any object with `debug`, `error`, `info`, `verbose` and `warn` methods — see [Logging](#logging). | | `log` | silent | Any object with `debug`, `error`, `info`, `verbose` and `warn` methods — see [Logging](#logging). |
| `signal` | — | An `AbortSignal` that cancels connecting and tears the session down. | | `signal` | — | An `AbortSignal` that cancels connecting and tears the session down. |
+5 -4
View File
@@ -69,6 +69,9 @@ function delay(ms: number): Promise<void> {
return new Promise(resolve => { setTimeout(resolve, ms); }); return new Promise(resolve => { setTimeout(resolve, ms); });
} }
/** A cmd_length below the 16-octet header: a stream no framing can recover from. */
const unreadablePdu = Buffer.from([0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1]);
/** The server's side of the one connection under test. */ /** The server's side of the one connection under test. */
function peerOf(smpp: SmppServer): Session { function peerOf(smpp: SmppServer): Session {
const [peer] = smpp.sessions; const [peer] = smpp.sessions;
@@ -402,8 +405,7 @@ describe('reconnect', () => {
const reconnected = once<true>(resolve => { session.on('reconnected', () => { resolve(true); }); }); const reconnected = once<true>(resolve => { session.on('reconnected', () => { resolve(true); }); });
// A cmd_length below the 16-octet header is a stream no framing can recover from. peerOf(smpp).sock.write(unreadablePdu);
peerOf(smpp).sock.write(Buffer.from([0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1]));
await reconnected; await reconnected;
assert.deepEqual(events, ['sessionError']); assert.deepEqual(events, ['sessionError']);
@@ -448,8 +450,7 @@ describe('reconnect', () => {
const closed = once<true>(resolve => { session.on('close', () => { resolve(true); }); }); const closed = once<true>(resolve => { session.on('close', () => { resolve(true); }); });
// A cmd_length below the 16-octet header: unreadable, and nothing left to retry it. peerOf(smpp).sock.write(unreadablePdu);
peerOf(smpp).sock.write(Buffer.from([0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1]));
await closed; await closed;
assert.equal(disconnects, 0); assert.equal(disconnects, 0);
-1
View File
@@ -1374,7 +1374,6 @@ describe('application hooks that throw or reject', () => {
}); });
test('keeps backing off when every link dies as soon as it comes up', async t => { test('keeps backing off when every link dies as soon as it comes up', async t => {
// A stream we cannot read is found after the bind, so a bind alone must not prove the link.
const clock = { now: 0 }; const clock = { now: 0 };
const delays: number[] = []; const delays: number[] = [];
const noop = (): void => undefined; const noop = (): void => undefined;