| name | websocket-reconnect |
| description | WebSocket connection management with exponential backoff + jitter retry, heartbeat detection, and circuit breaker pattern. Use when you need reliable WebSocket connections that automatically recover from network failures. |
| license | MIT |
| metadata | {"author":"custom","version":"1.0.0","openclaw":{"emoji":"🔌","requires":{"bins":"[Truncated]"}}} |
WebSocket Reconnect Skill
可靠的 WebSocket 连接管理,包含指数退避 + 抖动重连算法、心跳检测和断路器模式。
特性
- 指数退避重连: 智能重试策略,延迟时间指数增长
- 随机抖动 (Jitter): 防止群震问题 (thundering herd)
- 心跳检测: 自动检测僵死连接并触发重连
- 断路器模式: 三次状态 (CLOSED, OPEN, HALF-OPEN) 防止级联故障
- 最大重试上限: 避免无限重试消耗资源
- 事件驱动: 完整的事件系统用于状态监控
安装依赖
npm install ws
快速开始
基础用法
const { WebSocketReconnect } = require('./scripts/websocket-reconnect.js');
const ws = new WebSocketReconnect({
url: 'wss://api.example.com/socket',
maxRetries: 10,
baseDelay: 1000,
maxDelay: 30000
});
ws.on('open', () => {
console.log('✅ Connected');
});
ws.on('message', (event) => {
console.log('📨 Message:', event.data);
});
ws.on('close', (event) => {
console.log('❌ Closed:', event.code, event.reason);
});
ws.on('error', (error) => {
console.error('⚠️ Error:', error.message);
});
ws.on('retry', (info) => {
console.log(`🔄 Retry ${info.attempt}/${info.maxRetries} in ${info.delay}ms`);
});
ws.connect();
ws.send(JSON.stringify({ type: 'subscribe', channel: 'updates' }));
完整配置示例
const ws = new WebSocketReconnect({
url: 'wss://api.example.com/socket',
protocols: ['graphql-ws'],
websocketOptions: {
headers: {
'Authorization': 'Bearer token123'
}
},
maxRetries: 10,
baseDelay: 1000,
maxDelay: 30000,
multiplier: 2,
jitter: 0.1,
heartbeatInterval: 30000,
heartbeatTimeout: 5000,
heartbeatMessage: JSON.stringify({ type: 'ping' }),
circuitBreaker: {
failureThreshold: 5,
resetTimeout: 60000,
halfOpenMaxRequests: 3
}
});
重连策略
指数退避计算
重连延迟按指数增长,避免频繁重试:
延迟 = baseDelay × (multiplier ^ 尝试次数)
示例 (baseDelay=1000ms, multiplier=2):
- 第 1 次重试:1000ms (1 秒)
- 第 2 次重试:2000ms (2 秒)
- 第 3 次重试:4000ms (4 秒)
- 第 4 次重试:8000ms (8 秒)
- ...
- 达到 maxDelay 后不再增长
抖动 (Jitter)
添加随机抖动防止多个客户端同时重试:
实际延迟 = 计算延迟 × (0.9 ~ 1.1)
心跳检测机制
工作原理
- 连接成功后,每隔
heartbeatInterval 发送 ping 消息
- 等待服务器在
heartbeatTimeout 内回复 pong
- 如果超时,认为连接已僵死,自动关闭并触发重连
服务器端要求
服务器需要响应 ping 消息:
wss.on('connection', (ws) => {
ws.on('message', (data) => {
const message = JSON.parse(data);
if (message.type === 'ping') {
ws.send(JSON.stringify({ type: 'pong' }));
}
});
});
自定义心跳消息
如果服务器使用不同的心跳协议:
const ws = new WebSocketReconnect({
url: 'wss://api.example.com',
heartbeatInterval: 30000,
heartbeatMessage: 'PING',
heartbeatMessage: { cmd: 'heartbeat' }
});
ws.on('message', (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') {
console.log('Heartbeat OK');
}
});
断路器模式
三种状态
CLOSED (正常)
OPEN (熔断)
- 请求立即失败,不尝试连接
- 防止对故障服务的过载
- 经过
resetTimeout 后自动转为 HALF-OPEN
HALF-OPEN (测试)
- 允许有限数量的请求通过
- 成功则转为 CLOSED
- 失败则转回 OPEN
状态监控
ws.on('circuitChange', (state) => {
console.log(`Circuit breaker state: ${state}`);
if (state === 'OPEN') {
console.log('⚠️ Service temporarily unavailable');
}
});
const circuitState = ws.getCircuitState();
手动控制断路器
ws.openCircuit();
ws.closeCircuit();
事件参考
| 事件 | 参数 | 描述 |
|---|
open | 无 | 连接成功建立 |
message | event | 收到消息 (原生 MessageEvent) |
close | {code, reason} | 连接关闭 |
error | Error | 发生错误 |
retry | {attempt, delay, maxRetries} | 即将重试 |
stateChange | state | 连接状态变化 |
circuitChange | state | 断路器状态变化 |
状态监控
获取统计信息
const stats = ws.getStats();
console.log(stats);
连接状态
CLOSED: 未连接
CONNECTING: 正在连接
OPEN: 已连接
CLOSING: 正在关闭
BLOCKED: 被断路器阻止
FAILED: 超过最大重试次数
完整示例
实时聊天客户端
const { WebSocketReconnect } = require('./scripts/websocket-reconnect.js');
class ChatClient {
constructor(userId) {
this.userId = userId;
this.ws = new WebSocketReconnect({
url: `wss://chat.example.com/socket?user=${userId}`,
maxRetries: 10,
baseDelay: 1000,
maxDelay: 30000,
heartbeatInterval: 30000,
heartbeatTimeout: 5000,
circuitBreaker: {
failureThreshold: 5,
resetTimeout: 60000
}
});
this.setupEventHandlers();
}
setupEventHandlers() {
this.ws.on('open', () => {
console.log('✅ Connected to chat server');
this.ws.send(JSON.stringify({
: ,
: .
}));
});
..(, {
message = .(event.);
.(message);
});
..(, {
.();
});
..(, {
.(, error.);
});
..(, {
.();
});
..(, {
(state === ) {
.();
}
});
}
() {
(message.) {
:
;
:
.();
;
:
.();
;
}
}
() {
(.. === ) {
..(.({
: ,
: content
}));
} {
.();
}
}
() {
..();
}
() {
..();
}
}
chat = ();
chat.();
chat.();
GraphQL 订阅客户端
const { WebSocketReconnect } = require('./scripts/websocket-reconnect.js');
class GraphQLSubscriptionClient {
constructor(endpoint, options = {}) {
this.ws = new WebSocketReconnect({
url: endpoint,
protocols: ['graphql-ws'],
maxRetries: options.maxRetries || 10,
heartbeatInterval: options.heartbeatInterval || 30000,
heartbeatMessage: JSON.stringify({ type: 'connection_init' }),
...options
});
this.subscriptions = new Map();
this.subscriptionId = 0;
this.setupEventHandlers();
}
setupEventHandlers() {
this.ws.on('open', () => {
console.log('✅ GraphQL WebSocket connected');
this.resubscribeAll();
});
..(, {
message = .(event.);
.(message);
});
}
() {
(message.) {
:
.();
;
:
subscription = ..(message.);
(subscription && subscription.) {
subscription.(message.);
}
;
:
sub = ..(message.);
(sub && sub.) {
sub.();
}
..(message.);
;
:
s = ..(message.);
(s && s.) {
s.(message.);
}
;
}
}
() {
id = (++.);
..(id, {
query,
variables,
: callbacks.,
: callbacks.,
: callbacks.
});
(.. === ) {
..(.({
id,
: ,
: { query, variables }
}));
}
.(id);
}
() {
..(id);
(.. === ) {
..(.({
id,
:
}));
}
}
() {
( [id, sub] .) {
..(.({
id,
: ,
: { : sub., : sub. }
}));
}
}
() {
..();
}
() {
..();
}
}
配置选项
| 选项 | 类型 | 默认值 | 描述 |
|---|
url | string | 必填 | WebSocket 服务器 URL |
protocols | array | [] | 子协议列表 |
websocketOptions | object | {} | WebSocket 构造函数选项 (Node.js) |
maxRetries | number | 10 | 最大重试次数 |
baseDelay | number | 1000 | 基础延迟 (毫秒) |
maxDelay | number | 30000 | 最大延迟 (毫秒) |
multiplier | number | 2 | 退避倍数 |
jitter | number | 0.1 | 抖动系数 (0-1) |
heartbeatInterval | number | 30000 | 心跳间隔 (毫秒) |
heartbeatTimeout | number | 5000 | 心跳超时 (毫秒) |
heartbeatMessage | string | {"type":"ping"} | 心跳消息 |
circuitBreaker.failureThreshold | number | 5 | 打开断路器的失败次数 |
circuitBreaker.resetTimeout | number | 60000 | 断路器重置超时 (毫秒) |
circuitBreaker.halfOpenMaxRequests | number | 3 | 半开状态最大请求数 |
最佳实践
1. 合理设置重试次数
maxRetries: 20, baseDelay: 2000
maxRetries: 5, baseDelay: 1000
2. 心跳间隔选择
heartbeatInterval: 10000, heartbeatTimeout: 3000
heartbeatInterval: 30000, heartbeatTimeout: 5000
heartbeatInterval: 60000, heartbeatTimeout: 10000
3. 断路器阈值
circuitBreaker: { failureThreshold: 3, resetTimeout: 30000 }
circuitBreaker: { failureThreshold: 10, resetTimeout: 120000 }
4. 优雅关闭
ws.close(1001, 'Client shutting down');
process.exit();
故障排查
问题:频繁重连
原因: 服务器不稳定或网络问题
解决:
- 增加
baseDelay 和 maxDelay
- 降低
maxRetries
- 检查服务器日志
问题:心跳超时
原因: 服务器未响应 ping 或网络延迟高
解决:
- 增加
heartbeatTimeout
- 确认服务器正确响应 ping
- 检查网络质量
问题:断路器持续 OPEN
原因: 服务持续故障
解决:
- 检查服务健康状态
- 增加
failureThreshold
- 减少
resetTimeout 更快尝试恢复
性能影响
内存占用
每个实例约 1-2MB (包括事件处理器和定时器)
CPU 占用
- 空闲连接:几乎为零 (仅心跳定时器)
- 重连期间:低 (指数退避减少重试频率)
网络流量
- 心跳:每 30 秒约 100 字节
- 重连:根据网络状况动态调整
浏览器兼容性
支持所有现代浏览器 (Chrome, Firefox, Safari, Edge) 和 Node.js 14+
许可证
MIT