Generic stream reconnection module that provides intelligent reconnection logic with configurable backoff strategies.
npx @tessl/cli install tessl/npm-reconnect-core@1.3.0Reconnect Core is a generic stream reconnection module that provides intelligent reconnection logic with configurable backoff strategies. It serves as a foundation for building specialized reconnection libraries for TCP, WebSocket, and other network protocols, handling connection state management and automatic reconnection with robust error handling.
npm install reconnect-coreconst inject = require('reconnect-core');For ES modules:
import inject from 'reconnect-core';const inject = require('reconnect-core');
const net = require('net');
// Create a TCP reconnection module
const reconnect = inject(function() {
// Arguments are passed from .connect() call
// 'this' refers to the reconnect emitter instance
return net.connect.apply(null, arguments);
});
// Create a reconnection instance
const connection = reconnect({
initialDelay: 1000,
maxDelay: 30000,
strategy: 'fibonacci'
}, function(stream) {
// Handle connected stream
console.log('Connected!');
stream.on('data', function(data) {
console.log('Received:', data.toString());
});
})
.on('connect', function(con) {
console.log('Connection established');
})
.on('reconnect', function(n, delay) {
console.log(`Reconnection attempt ${n}, delay: ${delay}ms`);
})
.on('disconnect', function(err) {
console.log('Disconnected:', err?.message);
})
.on('error', function(err) {
console.log('Connection error:', err.message);
});
// Start connecting
connection.connect(8080, 'localhost');
// Later: stop reconnecting
connection.disconnect();Reconnect Core follows an injection pattern where users provide their own connection creation function. The module wraps this function with:
backoff library for intelligent retry timingThe main export is a factory function that creates reconnection modules by injecting a connection creation function.
/**
* Creates a reconnection module by injecting a connection creation function
* @param {Function} createConnection - Function that creates the underlying connection
* @returns {Function} Reconnection function that creates reconnection instances
*/
function inject(createConnection);The createConnection function signature:
.connect() methodthis bound to the reconnect emitter instanceThe injected function returns a reconnection function that creates reconnection instances.
/**
* Creates a reconnection instance with specified options and callback
* @param {Object|Function} opts - Configuration options or connection callback
* @param {Function} [onConnect] - Optional connection callback function
* @returns {ReconnectEmitter} EventEmitter instance with reconnection capabilities
*/
function reconnect(opts, onConnect);interface ReconnectOptions {
/** Initial delay before first reconnection attempt (default: 1000ms) */
initialDelay?: number;
/** Maximum delay between reconnection attempts (default: 30000ms) */
maxDelay?: number;
/** Backoff strategy: 'fibonacci', 'exponential', or custom backoff instance */
strategy?: string | BackoffStrategy;
/** Alias for strategy */
type?: string | BackoffStrategy;
/** Number of failed attempts before giving up (default: undefined/unlimited) */
failAfter?: number;
/** Randomization factor for backoff delays (0-1) */
randomisationFactor?: number;
/** Whether to treat connection as immediately connected (default: false) */
immediate?: boolean;
/** Alternative way to specify connection callback */
onConnect?: Function;
}The reconnection function returns an EventEmitter instance with additional properties and methods.
interface ReconnectEmitter extends EventEmitter {
/** Current connection state (read-only) */
connected: boolean;
/** Whether to continue reconnecting (read-write) */
reconnect: boolean;
/** Reference to current underlying connection (internal) */
_connection?: any;
/**
* Start connection/reconnection process
* @param {...any} args - Arguments passed to createConnection function
* @returns {ReconnectEmitter} Self for chaining
*/
connect(...args): ReconnectEmitter;
/**
* Alias for connect method
* @param {...any} args - Arguments passed to createConnection function
* @returns {ReconnectEmitter} Self for chaining
*/
listen(...args): ReconnectEmitter;
/**
* Stop reconnecting and end current connection
* @returns {ReconnectEmitter} Self for chaining
*/
disconnect(): ReconnectEmitter;
/**
* Reset backoff timer and attempt immediate reconnection
* @returns {undefined} No return value
*/
reset(): void;
}The reconnect emitter instance emits the following events:
// Connection established successfully
emitter.on('connect', (connection) => {});
emitter.on('connection', (connection) => {}); // Alias for 'connect'
// Before each reconnection attempt
emitter.on('reconnect', (attemptNumber, delay) => {});
// Connection lost or ended
emitter.on('disconnect', (error) => {});
// Connection error occurred
emitter.on('error', (error) => {});
// Backoff process events (from backoff library)
emitter.on('backoff', (attemptNumber, delay, error) => {});
// Maximum attempts reached, giving up
emitter.on('fail', (error) => {});Event Details:
'connect'/'connection': Emitted when connection is successfully established
connection: The underlying connection object returned by createConnection'reconnect': Emitted before each reconnection attempt
attemptNumber: Current attempt number (starts at 0)delay: Delay used before this attempt (in milliseconds)'disconnect': Emitted when connection is lost or closed
error: Optional error object if disconnection was due to an error'error': Emitted when connection errors occur
error: Error object describing the failure'backoff': Emitted during backoff timing process
attemptNumber: Current attempt numberdelay: Delay being usederror: Error that triggered the backoff'fail': Emitted when failAfter limit is reached
error: Final error before giving upReconnect Core integrates with the backoff library and supports multiple strategies:
// Built-in strategies (pass as string to 'strategy' option)
type BuiltInStrategy = 'fibonacci' | 'exponential';
// Custom backoff strategy interface
interface BackoffStrategy {
/** Calculate next delay value */
next(): number;
/** Reset the strategy to initial state */
reset(): void;
}Strategy Examples:
// Fibonacci backoff (default)
const connection = reconnect({ strategy: 'fibonacci' });
// Exponential backoff
const connection = reconnect({ strategy: 'exponential' });
// Custom strategy
const customStrategy = {
next: function() { return 5000; }, // Always 5 seconds
reset: function() { }
};
const connection = reconnect({
strategy: new (require('backoff')).Backoff(customStrategy)
});const inject = require('reconnect-core');
const net = require('net');
const reconnect = inject(() => net.connect.apply(null, arguments));
const connection = reconnect().connect(8080, 'localhost');const inject = require('reconnect-core');
const WebSocket = require('ws');
const reconnect = inject((url) => new WebSocket(url));
const connection = reconnect({ immediate: true }, (ws) => {
ws.send('Hello Server!');
}).connect('ws://localhost:8080');const inject = require('reconnect-core');
const http = require('http');
const reconnect = inject((options) => http.request(options));
const connection = reconnect({ immediate: true }, (req) => {
req.write('POST data');
req.end();
}).connect({ host: 'localhost', port: 8080, method: 'POST' });const connection = reconnect({
initialDelay: 500,
maxDelay: 60000,
strategy: 'exponential',
failAfter: 10,
randomisationFactor: 0.2,
immediate: false
}, function(stream) {
// Handle connection
})
.on('connect', (con) => console.log('Connected'))
.on('reconnect', (n, delay) => console.log(`Attempt ${n}, delay: ${delay}ms`))
.on('disconnect', (err) => console.log('Disconnected:', err?.message))
.on('fail', (err) => console.log('Max attempts reached, giving up'))
.connect(port, host);
// Manual control
setTimeout(() => {
connection.reconnect = false; // Disable auto-reconnection
connection.disconnect(); // Disconnect immediately
}, 30000);
// Force immediate reconnection
connection.reset();