@procwire/transport 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/framing/line-delimited.d.ts.map +1 -1
- package/dist/framing/line-delimited.js.map +1 -1
- package/dist/heartbeat/constants.d.ts +12 -0
- package/dist/heartbeat/constants.d.ts.map +1 -0
- package/dist/heartbeat/constants.js +17 -0
- package/dist/heartbeat/constants.js.map +1 -0
- package/dist/heartbeat/index.d.ts +10 -0
- package/dist/heartbeat/index.d.ts.map +1 -0
- package/dist/heartbeat/index.js +10 -0
- package/dist/heartbeat/index.js.map +1 -0
- package/dist/heartbeat/manager.d.ts +107 -0
- package/dist/heartbeat/manager.d.ts.map +1 -0
- package/dist/heartbeat/manager.js +252 -0
- package/dist/heartbeat/manager.js.map +1 -0
- package/dist/heartbeat/types.d.ts +99 -0
- package/dist/heartbeat/types.d.ts.map +1 -0
- package/dist/heartbeat/types.js +8 -0
- package/dist/heartbeat/types.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/process/manager.d.ts.map +1 -1
- package/dist/process/manager.js +2 -1
- package/dist/process/manager.js.map +1 -1
- package/dist/protocol/index.d.ts +2 -0
- package/dist/protocol/index.d.ts.map +1 -1
- package/dist/protocol/index.js +3 -0
- package/dist/protocol/index.js.map +1 -1
- package/dist/protocol/reserved-methods.d.ts +90 -0
- package/dist/protocol/reserved-methods.d.ts.map +1 -0
- package/dist/protocol/reserved-methods.js +99 -0
- package/dist/protocol/reserved-methods.js.map +1 -0
- package/dist/protocol/reserved-types.d.ts +231 -0
- package/dist/protocol/reserved-types.d.ts.map +1 -0
- package/dist/protocol/reserved-types.js +10 -0
- package/dist/protocol/reserved-types.js.map +1 -0
- package/dist/reconnect/constants.d.ts +12 -0
- package/dist/reconnect/constants.d.ts.map +1 -0
- package/dist/reconnect/constants.js +21 -0
- package/dist/reconnect/constants.js.map +1 -0
- package/dist/reconnect/index.d.ts +10 -0
- package/dist/reconnect/index.d.ts.map +1 -0
- package/dist/reconnect/index.js +10 -0
- package/dist/reconnect/index.js.map +1 -0
- package/dist/reconnect/manager.d.ts +110 -0
- package/dist/reconnect/manager.d.ts.map +1 -0
- package/dist/reconnect/manager.js +264 -0
- package/dist/reconnect/manager.js.map +1 -0
- package/dist/reconnect/types.d.ts +137 -0
- package/dist/reconnect/types.d.ts.map +1 -0
- package/dist/reconnect/types.js +8 -0
- package/dist/reconnect/types.js.map +1 -0
- package/dist/resilience/handle.d.ts +112 -0
- package/dist/resilience/handle.d.ts.map +1 -0
- package/dist/resilience/handle.js +371 -0
- package/dist/resilience/handle.js.map +1 -0
- package/dist/resilience/index.d.ts +9 -0
- package/dist/resilience/index.d.ts.map +1 -0
- package/dist/resilience/index.js +9 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/resilience/types.d.ts +191 -0
- package/dist/resilience/types.d.ts.map +1 -0
- package/dist/resilience/types.js +8 -0
- package/dist/resilience/types.js.map +1 -0
- package/dist/shutdown/constants.d.ts +12 -0
- package/dist/shutdown/constants.d.ts.map +1 -0
- package/dist/shutdown/constants.js +15 -0
- package/dist/shutdown/constants.js.map +1 -0
- package/dist/shutdown/index.d.ts +10 -0
- package/dist/shutdown/index.d.ts.map +1 -0
- package/dist/shutdown/index.js +10 -0
- package/dist/shutdown/index.js.map +1 -0
- package/dist/shutdown/manager.d.ts +102 -0
- package/dist/shutdown/manager.d.ts.map +1 -0
- package/dist/shutdown/manager.js +252 -0
- package/dist/shutdown/manager.js.map +1 -0
- package/dist/shutdown/types.d.ts +133 -0
- package/dist/shutdown/types.d.ts.map +1 -0
- package/dist/shutdown/types.js +8 -0
- package/dist/shutdown/types.js.map +1 -0
- package/dist/transport/socket-transport.d.ts.map +1 -1
- package/dist/transport/socket-transport.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReconnectManager implementation.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
* @module Reconnect
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from "../utils/events.js";
|
|
8
|
+
import type { ReconnectOptions, ReconnectState, ReconnectEventMap, Reconnectable } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Manages automatic reconnection with exponential backoff and request queueing.
|
|
11
|
+
*
|
|
12
|
+
* The ReconnectManager implements exponential backoff with jitter to handle
|
|
13
|
+
* transient connection failures. It can optionally queue requests during
|
|
14
|
+
* reconnection and execute them once the connection is restored.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const reconnect = new ReconnectManager(dataTransport, {
|
|
19
|
+
* initialDelay: 100,
|
|
20
|
+
* maxDelay: 30000,
|
|
21
|
+
* maxAttempts: 10,
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* reconnect.on('reconnect:success', ({ attempt }) => {
|
|
25
|
+
* console.log(`Reconnected after ${attempt} attempts`);
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* reconnect.on('reconnect:failed', ({ lastError }) => {
|
|
29
|
+
* console.error('Reconnection failed:', lastError);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // When disconnect is detected:
|
|
33
|
+
* const success = await reconnect.handleDisconnect(error);
|
|
34
|
+
* if (!success) {
|
|
35
|
+
* // Handle permanent failure
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class ReconnectManager extends EventEmitter<ReconnectEventMap> {
|
|
40
|
+
private readonly options;
|
|
41
|
+
private readonly target;
|
|
42
|
+
private readonly requestQueue;
|
|
43
|
+
private state;
|
|
44
|
+
private cancelled;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new ReconnectManager.
|
|
47
|
+
*
|
|
48
|
+
* @param target - Object that can be reconnected (has connect() method)
|
|
49
|
+
* @param options - Configuration options (merged with defaults)
|
|
50
|
+
*/
|
|
51
|
+
constructor(target: Reconnectable, options?: Partial<ReconnectOptions>);
|
|
52
|
+
/**
|
|
53
|
+
* Handle unexpected disconnect. Initiates reconnection if enabled.
|
|
54
|
+
*
|
|
55
|
+
* @param error - The error that caused the disconnect
|
|
56
|
+
* @returns Promise that resolves to true if reconnected, false if failed
|
|
57
|
+
*/
|
|
58
|
+
handleDisconnect(error: Error): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Queue a request to be executed after reconnection.
|
|
61
|
+
* Returns null if not currently reconnecting or queueing is disabled.
|
|
62
|
+
*
|
|
63
|
+
* @param method - Method name for logging
|
|
64
|
+
* @param execute - Function that executes the request
|
|
65
|
+
* @returns Promise that resolves with request result, or null if not queued
|
|
66
|
+
*/
|
|
67
|
+
queueRequest<T>(method: string, execute: () => Promise<T>): Promise<T> | null;
|
|
68
|
+
/**
|
|
69
|
+
* Get current reconnection state (readonly).
|
|
70
|
+
*/
|
|
71
|
+
getState(): Readonly<ReconnectState>;
|
|
72
|
+
/**
|
|
73
|
+
* Get current options (readonly).
|
|
74
|
+
*/
|
|
75
|
+
getOptions(): Readonly<Required<ReconnectOptions>>;
|
|
76
|
+
/**
|
|
77
|
+
* Check if currently reconnecting.
|
|
78
|
+
*/
|
|
79
|
+
isReconnecting(): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Cancel ongoing reconnection attempt.
|
|
82
|
+
* Rejects all queued requests.
|
|
83
|
+
*/
|
|
84
|
+
cancel(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Reset state for restart scenarios.
|
|
87
|
+
*/
|
|
88
|
+
reset(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Calculate delay for current attempt using exponential backoff with jitter.
|
|
91
|
+
*/
|
|
92
|
+
private calculateDelay;
|
|
93
|
+
/**
|
|
94
|
+
* Flush queued requests after successful reconnection.
|
|
95
|
+
*/
|
|
96
|
+
private flushQueue;
|
|
97
|
+
/**
|
|
98
|
+
* Reject all queued requests with given error.
|
|
99
|
+
*/
|
|
100
|
+
private rejectQueue;
|
|
101
|
+
/**
|
|
102
|
+
* Remove a specific request from the queue.
|
|
103
|
+
*/
|
|
104
|
+
private removeFromQueue;
|
|
105
|
+
/**
|
|
106
|
+
* Sleep for specified milliseconds.
|
|
107
|
+
*/
|
|
108
|
+
private sleep;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/reconnect/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EAEjB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,iBAAiB,CAAC;IACnE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuB;IAEpD,OAAO,CAAC,KAAK,CAMX;IAEF,OAAO,CAAC,SAAS,CAAS;IAE1B;;;;;OAKG;gBACS,MAAM,EAAE,aAAa,EAAE,OAAO,GAAE,OAAO,CAAC,gBAAgB,CAAM;IAM1E;;;;;OAKG;IACG,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IA8DtD;;;;;;;OAOG;IACH,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI;IA+C7E;;OAEG;IACH,QAAQ,IAAI,QAAQ,CAAC,cAAc,CAAC;IAIpC;;OAEG;IACH,UAAU,IAAI,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAIlD;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;;OAGG;IACH,MAAM,IAAI,IAAI;IASd;;OAEG;IACH,KAAK,IAAI,IAAI;IAYb;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;YACW,UAAU;IAiBxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;OAEG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReconnectManager implementation.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
* @module Reconnect
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from "../utils/events.js";
|
|
8
|
+
import { DEFAULT_RECONNECT_OPTIONS } from "./constants.js";
|
|
9
|
+
/**
|
|
10
|
+
* Manages automatic reconnection with exponential backoff and request queueing.
|
|
11
|
+
*
|
|
12
|
+
* The ReconnectManager implements exponential backoff with jitter to handle
|
|
13
|
+
* transient connection failures. It can optionally queue requests during
|
|
14
|
+
* reconnection and execute them once the connection is restored.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const reconnect = new ReconnectManager(dataTransport, {
|
|
19
|
+
* initialDelay: 100,
|
|
20
|
+
* maxDelay: 30000,
|
|
21
|
+
* maxAttempts: 10,
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* reconnect.on('reconnect:success', ({ attempt }) => {
|
|
25
|
+
* console.log(`Reconnected after ${attempt} attempts`);
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* reconnect.on('reconnect:failed', ({ lastError }) => {
|
|
29
|
+
* console.error('Reconnection failed:', lastError);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // When disconnect is detected:
|
|
33
|
+
* const success = await reconnect.handleDisconnect(error);
|
|
34
|
+
* if (!success) {
|
|
35
|
+
* // Handle permanent failure
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class ReconnectManager extends EventEmitter {
|
|
40
|
+
options;
|
|
41
|
+
target;
|
|
42
|
+
requestQueue = [];
|
|
43
|
+
state = {
|
|
44
|
+
attempt: 0,
|
|
45
|
+
isReconnecting: false,
|
|
46
|
+
reconnectStartedAt: null,
|
|
47
|
+
queueSize: 0,
|
|
48
|
+
lastError: null,
|
|
49
|
+
};
|
|
50
|
+
cancelled = false;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new ReconnectManager.
|
|
53
|
+
*
|
|
54
|
+
* @param target - Object that can be reconnected (has connect() method)
|
|
55
|
+
* @param options - Configuration options (merged with defaults)
|
|
56
|
+
*/
|
|
57
|
+
constructor(target, options = {}) {
|
|
58
|
+
super();
|
|
59
|
+
this.target = target;
|
|
60
|
+
this.options = { ...DEFAULT_RECONNECT_OPTIONS, ...options };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Handle unexpected disconnect. Initiates reconnection if enabled.
|
|
64
|
+
*
|
|
65
|
+
* @param error - The error that caused the disconnect
|
|
66
|
+
* @returns Promise that resolves to true if reconnected, false if failed
|
|
67
|
+
*/
|
|
68
|
+
async handleDisconnect(error) {
|
|
69
|
+
if (!this.options.enabled || this.state.isReconnecting) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
this.cancelled = false;
|
|
73
|
+
this.state.isReconnecting = true;
|
|
74
|
+
this.state.reconnectStartedAt = Date.now();
|
|
75
|
+
this.state.attempt = 0;
|
|
76
|
+
this.state.lastError = error;
|
|
77
|
+
while (this.state.attempt < this.options.maxAttempts && !this.cancelled) {
|
|
78
|
+
this.state.attempt++;
|
|
79
|
+
const delay = this.calculateDelay();
|
|
80
|
+
this.emit("reconnect:attempting", {
|
|
81
|
+
attempt: this.state.attempt,
|
|
82
|
+
delay,
|
|
83
|
+
error: this.state.lastError,
|
|
84
|
+
});
|
|
85
|
+
await this.sleep(delay);
|
|
86
|
+
// Check if cancelled during sleep
|
|
87
|
+
if (this.cancelled) {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
// Check cancellation again right before connect
|
|
92
|
+
if (this.cancelled) {
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
await this.target.connect();
|
|
96
|
+
const totalTimeMs = Date.now() - this.state.reconnectStartedAt;
|
|
97
|
+
this.emit("reconnect:success", {
|
|
98
|
+
attempt: this.state.attempt,
|
|
99
|
+
totalTimeMs,
|
|
100
|
+
});
|
|
101
|
+
this.state.isReconnecting = false;
|
|
102
|
+
await this.flushQueue();
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
catch (connectError) {
|
|
106
|
+
this.state.lastError = connectError;
|
|
107
|
+
// Continue to next attempt
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Max attempts exceeded or cancelled
|
|
111
|
+
this.emit("reconnect:failed", {
|
|
112
|
+
attempts: this.state.attempt,
|
|
113
|
+
lastError: this.state.lastError,
|
|
114
|
+
});
|
|
115
|
+
this.state.isReconnecting = false;
|
|
116
|
+
this.rejectQueue(this.state.lastError);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Queue a request to be executed after reconnection.
|
|
121
|
+
* Returns null if not currently reconnecting or queueing is disabled.
|
|
122
|
+
*
|
|
123
|
+
* @param method - Method name for logging
|
|
124
|
+
* @param execute - Function that executes the request
|
|
125
|
+
* @returns Promise that resolves with request result, or null if not queued
|
|
126
|
+
*/
|
|
127
|
+
queueRequest(method, execute) {
|
|
128
|
+
if (!this.state.isReconnecting || !this.options.queueRequests) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
if (this.requestQueue.length >= this.options.maxQueueSize) {
|
|
132
|
+
throw new Error(`Request queue full (max ${this.options.maxQueueSize}). ` +
|
|
133
|
+
`Consider increasing maxQueueSize or reducing request rate.`);
|
|
134
|
+
}
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
const queuedAt = Date.now();
|
|
137
|
+
const timeoutHandle = setTimeout(() => {
|
|
138
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
|
+
this.removeFromQueue(request);
|
|
140
|
+
const waitedMs = Date.now() - queuedAt;
|
|
141
|
+
this.emit("reconnect:request-timeout", { method, waitedMs });
|
|
142
|
+
reject(new Error(`Request '${method}' timed out after ${waitedMs}ms waiting for reconnection`));
|
|
143
|
+
}, this.options.queueTimeout);
|
|
144
|
+
const request = {
|
|
145
|
+
method,
|
|
146
|
+
execute,
|
|
147
|
+
resolve,
|
|
148
|
+
reject,
|
|
149
|
+
queuedAt,
|
|
150
|
+
timeoutHandle,
|
|
151
|
+
};
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
+
this.requestQueue.push(request);
|
|
154
|
+
this.state.queueSize = this.requestQueue.length;
|
|
155
|
+
this.emit("reconnect:request-queued", {
|
|
156
|
+
method,
|
|
157
|
+
queueSize: this.state.queueSize,
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get current reconnection state (readonly).
|
|
163
|
+
*/
|
|
164
|
+
getState() {
|
|
165
|
+
return { ...this.state, queueSize: this.requestQueue.length };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get current options (readonly).
|
|
169
|
+
*/
|
|
170
|
+
getOptions() {
|
|
171
|
+
return { ...this.options };
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Check if currently reconnecting.
|
|
175
|
+
*/
|
|
176
|
+
isReconnecting() {
|
|
177
|
+
return this.state.isReconnecting;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Cancel ongoing reconnection attempt.
|
|
181
|
+
* Rejects all queued requests.
|
|
182
|
+
*/
|
|
183
|
+
cancel() {
|
|
184
|
+
if (!this.state.isReconnecting) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.cancelled = true;
|
|
188
|
+
// Note: isReconnecting will be set to false when the loop exits
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Reset state for restart scenarios.
|
|
192
|
+
*/
|
|
193
|
+
reset() {
|
|
194
|
+
this.cancelled = false;
|
|
195
|
+
this.rejectQueue(new Error("ReconnectManager reset"));
|
|
196
|
+
this.state = {
|
|
197
|
+
attempt: 0,
|
|
198
|
+
isReconnecting: false,
|
|
199
|
+
reconnectStartedAt: null,
|
|
200
|
+
queueSize: 0,
|
|
201
|
+
lastError: null,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Calculate delay for current attempt using exponential backoff with jitter.
|
|
206
|
+
*/
|
|
207
|
+
calculateDelay() {
|
|
208
|
+
// Exponential backoff: initialDelay * multiplier^(attempt-1)
|
|
209
|
+
const exponentialDelay = this.options.initialDelay * Math.pow(this.options.multiplier, this.state.attempt - 1);
|
|
210
|
+
// Cap at maxDelay
|
|
211
|
+
const cappedDelay = Math.min(exponentialDelay, this.options.maxDelay);
|
|
212
|
+
// Add jitter: delay * (1 + random(-jitter, +jitter))
|
|
213
|
+
const jitterRange = cappedDelay * this.options.jitter;
|
|
214
|
+
const jitter = (Math.random() * 2 - 1) * jitterRange;
|
|
215
|
+
return Math.round(cappedDelay + jitter);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Flush queued requests after successful reconnection.
|
|
219
|
+
*/
|
|
220
|
+
async flushQueue() {
|
|
221
|
+
const queue = [...this.requestQueue];
|
|
222
|
+
this.requestQueue.length = 0;
|
|
223
|
+
this.state.queueSize = 0;
|
|
224
|
+
for (const request of queue) {
|
|
225
|
+
clearTimeout(request.timeoutHandle);
|
|
226
|
+
try {
|
|
227
|
+
const result = await request.execute();
|
|
228
|
+
request.resolve(result);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
request.reject(error);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Reject all queued requests with given error.
|
|
237
|
+
*/
|
|
238
|
+
rejectQueue(error) {
|
|
239
|
+
const queue = [...this.requestQueue];
|
|
240
|
+
this.requestQueue.length = 0;
|
|
241
|
+
this.state.queueSize = 0;
|
|
242
|
+
for (const request of queue) {
|
|
243
|
+
clearTimeout(request.timeoutHandle);
|
|
244
|
+
request.reject(error);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Remove a specific request from the queue.
|
|
249
|
+
*/
|
|
250
|
+
removeFromQueue(request) {
|
|
251
|
+
const index = this.requestQueue.indexOf(request);
|
|
252
|
+
if (index !== -1) {
|
|
253
|
+
this.requestQueue.splice(index, 1);
|
|
254
|
+
this.state.queueSize = this.requestQueue.length;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Sleep for specified milliseconds.
|
|
259
|
+
*/
|
|
260
|
+
sleep(ms) {
|
|
261
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/reconnect/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-reconnect manager types.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
* @module Reconnect
|
|
6
|
+
*/
|
|
7
|
+
import type { EventMap } from "../utils/events.js";
|
|
8
|
+
/**
|
|
9
|
+
* Configuration options for ReconnectManager.
|
|
10
|
+
*/
|
|
11
|
+
export interface ReconnectOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Enable auto-reconnect for data channel.
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
enabled: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Initial delay before first retry in milliseconds.
|
|
19
|
+
* @default 100
|
|
20
|
+
*/
|
|
21
|
+
initialDelay: number;
|
|
22
|
+
/**
|
|
23
|
+
* Maximum delay between retries in milliseconds.
|
|
24
|
+
* @default 30000
|
|
25
|
+
*/
|
|
26
|
+
maxDelay: number;
|
|
27
|
+
/**
|
|
28
|
+
* Backoff multiplier. Delay doubles each retry by default.
|
|
29
|
+
* @default 2
|
|
30
|
+
*/
|
|
31
|
+
multiplier: number;
|
|
32
|
+
/**
|
|
33
|
+
* Jitter factor (0-1) to randomize retry timing.
|
|
34
|
+
* Helps prevent thundering herd when multiple connections retry.
|
|
35
|
+
* @default 0.1
|
|
36
|
+
*/
|
|
37
|
+
jitter: number;
|
|
38
|
+
/**
|
|
39
|
+
* Maximum number of retry attempts. Use Infinity for unlimited.
|
|
40
|
+
* @default Infinity
|
|
41
|
+
*/
|
|
42
|
+
maxAttempts: number;
|
|
43
|
+
/**
|
|
44
|
+
* Queue requests while reconnecting instead of failing immediately.
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
queueRequests: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Maximum number of requests to queue during reconnect.
|
|
50
|
+
* @default 100
|
|
51
|
+
*/
|
|
52
|
+
maxQueueSize: number;
|
|
53
|
+
/**
|
|
54
|
+
* Timeout for queued requests in milliseconds.
|
|
55
|
+
* Requests waiting longer than this will be rejected.
|
|
56
|
+
* @default 60000
|
|
57
|
+
*/
|
|
58
|
+
queueTimeout: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Internal state of the ReconnectManager.
|
|
62
|
+
*/
|
|
63
|
+
export interface ReconnectState {
|
|
64
|
+
/** Current attempt number (1-based) */
|
|
65
|
+
attempt: number;
|
|
66
|
+
/** Whether currently attempting to reconnect */
|
|
67
|
+
isReconnecting: boolean;
|
|
68
|
+
/** Timestamp when reconnection started */
|
|
69
|
+
reconnectStartedAt: number | null;
|
|
70
|
+
/** Number of requests currently queued */
|
|
71
|
+
queueSize: number;
|
|
72
|
+
/** Last error that caused disconnect */
|
|
73
|
+
lastError: Error | null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Event map for ReconnectManager events.
|
|
77
|
+
*/
|
|
78
|
+
export interface ReconnectEventMap extends EventMap {
|
|
79
|
+
/**
|
|
80
|
+
* Emitted before each reconnection attempt.
|
|
81
|
+
*/
|
|
82
|
+
"reconnect:attempting": {
|
|
83
|
+
attempt: number;
|
|
84
|
+
delay: number;
|
|
85
|
+
error: Error;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Emitted after successful reconnection.
|
|
89
|
+
*/
|
|
90
|
+
"reconnect:success": {
|
|
91
|
+
attempt: number;
|
|
92
|
+
totalTimeMs: number;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Emitted when max attempts exceeded or unrecoverable error.
|
|
96
|
+
*/
|
|
97
|
+
"reconnect:failed": {
|
|
98
|
+
attempts: number;
|
|
99
|
+
lastError: Error;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Emitted when a request is queued during reconnection.
|
|
103
|
+
*/
|
|
104
|
+
"reconnect:request-queued": {
|
|
105
|
+
method: string;
|
|
106
|
+
queueSize: number;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Emitted when a queued request times out.
|
|
110
|
+
*/
|
|
111
|
+
"reconnect:request-timeout": {
|
|
112
|
+
method: string;
|
|
113
|
+
waitedMs: number;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Internal queued request representation.
|
|
118
|
+
*/
|
|
119
|
+
export interface QueuedRequest<T = unknown> {
|
|
120
|
+
method: string;
|
|
121
|
+
execute: () => Promise<T>;
|
|
122
|
+
resolve: (value: T) => void;
|
|
123
|
+
reject: (error: Error) => void;
|
|
124
|
+
queuedAt: number;
|
|
125
|
+
timeoutHandle: ReturnType<typeof setTimeout>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Interface for objects that can be reconnected.
|
|
129
|
+
* Used by ReconnectManager to abstract over different transport types.
|
|
130
|
+
*/
|
|
131
|
+
export interface Reconnectable {
|
|
132
|
+
/**
|
|
133
|
+
* Attempt to establish connection.
|
|
134
|
+
*/
|
|
135
|
+
connect(): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/reconnect/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAEhB,gDAAgD;IAChD,cAAc,EAAE,OAAO,CAAC;IAExB,0CAA0C;IAC1C,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,wCAAwC;IACxC,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD;;OAEG;IACH,sBAAsB,EAAE;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,KAAK,CAAC;KACd,CAAC;IAEF;;OAEG;IACH,mBAAmB,EAAE;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IAEF;;OAEG;IACH,kBAAkB,EAAE;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,KAAK,CAAC;KAClB,CAAC;IAEF;;OAEG;IACH,0BAA0B,EAAE;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF;;OAEG;IACH,2BAA2B,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/reconnect/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResilientProcessHandle implementation.
|
|
3
|
+
*
|
|
4
|
+
* Wraps a ProcessHandle with heartbeat monitoring, auto-reconnect,
|
|
5
|
+
* and graceful shutdown capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
* @module Resilience
|
|
9
|
+
*/
|
|
10
|
+
import type { ProcessHandle, ProcessState } from "../process/types.js";
|
|
11
|
+
import type { Channel } from "../channel/types.js";
|
|
12
|
+
import type { Unsubscribe } from "../utils/disposables.js";
|
|
13
|
+
import type { ShutdownReason } from "../protocol/reserved-types.js";
|
|
14
|
+
import type { IResilientProcessHandle, ResilientProcessEvents, ResilientProcessOptions } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Default resilient process options.
|
|
17
|
+
*
|
|
18
|
+
* Note: Reconnect is disabled by default for ProcessHandle because stdio-based
|
|
19
|
+
* transports cannot be reconnected. See createReconnectable() for details.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_RESILIENT_OPTIONS: Required<ResilientProcessOptions>;
|
|
22
|
+
/**
|
|
23
|
+
* A process handle with resilience features.
|
|
24
|
+
*
|
|
25
|
+
* Combines heartbeat monitoring, auto-reconnect, and graceful shutdown
|
|
26
|
+
* with a standard ProcessHandle.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const resilientHandle = new ResilientProcessHandle(processHandle, {
|
|
31
|
+
* heartbeat: { intervalMs: 5000, timeoutMs: 1000, maxMissed: 3 },
|
|
32
|
+
* reconnect: { maxAttempts: 5, initialDelay: 100 },
|
|
33
|
+
* shutdown: { gracefulTimeoutMs: 5000 },
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* resilientHandle.on('heartbeatDead', () => {
|
|
37
|
+
* console.log('Worker is unresponsive');
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* resilientHandle.on('reconnected', ({ attempt }) => {
|
|
41
|
+
* console.log(`Reconnected after ${attempt} attempts`);
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* resilientHandle.start();
|
|
45
|
+
*
|
|
46
|
+
* // Later
|
|
47
|
+
* await resilientHandle.shutdown('user_requested');
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class ResilientProcessHandle implements IResilientProcessHandle {
|
|
51
|
+
private readonly _handle;
|
|
52
|
+
private readonly events;
|
|
53
|
+
private heartbeatManager;
|
|
54
|
+
private reconnectManager;
|
|
55
|
+
private shutdownManager;
|
|
56
|
+
private readonly handleEventSubscriptions;
|
|
57
|
+
private readonly resilienceSubscriptions;
|
|
58
|
+
private _isHealthy;
|
|
59
|
+
private killFn;
|
|
60
|
+
/**
|
|
61
|
+
* Creates a new ResilientProcessHandle.
|
|
62
|
+
*
|
|
63
|
+
* @param handle - The underlying ProcessHandle
|
|
64
|
+
* @param options - Resilience configuration options
|
|
65
|
+
* @param killFn - Function to kill the process (injected for testability)
|
|
66
|
+
*/
|
|
67
|
+
constructor(handle: ProcessHandle, options?: ResilientProcessOptions, killFn?: (signal?: string) => void);
|
|
68
|
+
get id(): string;
|
|
69
|
+
get pid(): number | null;
|
|
70
|
+
get state(): ProcessState;
|
|
71
|
+
get isHealthy(): boolean;
|
|
72
|
+
get isReconnecting(): boolean;
|
|
73
|
+
get controlChannel(): Channel;
|
|
74
|
+
get dataChannel(): Channel | null;
|
|
75
|
+
get handle(): ProcessHandle;
|
|
76
|
+
/**
|
|
77
|
+
* Sends a request, optionally queueing during reconnection.
|
|
78
|
+
* Successful requests signal activity to the heartbeat manager (implicit heartbeat).
|
|
79
|
+
*/
|
|
80
|
+
request(method: string, params?: unknown, timeout?: number): Promise<unknown>;
|
|
81
|
+
notify(method: string, params?: unknown): Promise<void>;
|
|
82
|
+
requestViaData(method: string, params?: unknown, timeout?: number): Promise<unknown>;
|
|
83
|
+
/**
|
|
84
|
+
* Initiates graceful shutdown of the process.
|
|
85
|
+
*/
|
|
86
|
+
shutdown(reason?: ShutdownReason): Promise<void>;
|
|
87
|
+
close(): Promise<void>;
|
|
88
|
+
on<K extends keyof ResilientProcessEvents>(event: K, handler: (data: ResilientProcessEvents[K]) => void): Unsubscribe;
|
|
89
|
+
/**
|
|
90
|
+
* Starts resilience features.
|
|
91
|
+
*/
|
|
92
|
+
start(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Stops resilience features.
|
|
95
|
+
* Note: Base handle event forwarding continues after stop().
|
|
96
|
+
*/
|
|
97
|
+
stop(): void;
|
|
98
|
+
private setupHeartbeatListeners;
|
|
99
|
+
private setupReconnectListeners;
|
|
100
|
+
private setupShutdownListeners;
|
|
101
|
+
private setupHandleEventForwarding;
|
|
102
|
+
private setupHeartbeatPongListener;
|
|
103
|
+
/**
|
|
104
|
+
* Force kills the process with SIGKILL.
|
|
105
|
+
*/
|
|
106
|
+
private forceKill;
|
|
107
|
+
/**
|
|
108
|
+
* Cleanup all subscriptions (called by close()).
|
|
109
|
+
*/
|
|
110
|
+
private cleanupAllSubscriptions;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=handle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.d.ts","sourceRoot":"","sources":["../../src/resilience/handle.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAuB,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAGzF,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AA4DpB;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,uBAAuB,CAIvE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,sBAAuB,YAAW,uBAAuB;IACpE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8C;IAErE,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,eAAe,CAAgC;IAEvD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAqB;IAC9D,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAqB;IAC7D,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,MAAM,CAA4C;IAE1D;;;;;;OAMG;gBAED,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,uBAA4B,EACrC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI;IAyCpC,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,WAAW,IAAI,OAAO,GAAG,IAAI,CAEhC;IAED,IAAI,MAAM,IAAI,aAAa,CAE1B;IAED;;;OAGG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAsB7E,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO1F;;OAEG;IACG,QAAQ,CAAC,MAAM,GAAE,cAAiC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BlE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,EAAE,CAAC,CAAC,SAAS,MAAM,sBAAsB,EACvC,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GACjD,WAAW;IAId;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;;OAGG;IACH,IAAI,IAAI,IAAI;IAaZ,OAAO,CAAC,uBAAuB;IAkB/B,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,0BAA0B;IAgBlC,OAAO,CAAC,0BAA0B;IAsBlC;;OAEG;IACH,OAAO,CAAC,SAAS;IAYjB;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAWhC"}
|