@bernierllc/backoff-retry 0.1.1
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/CHANGELOG.md +7 -0
- package/LICENSE +7 -0
- package/README.md +345 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-protection.d.ts +69 -0
- package/dist/memory-protection.d.ts.map +1 -0
- package/dist/memory-protection.js +183 -0
- package/dist/memory-protection.js.map +1 -0
- package/dist/retry-manager.d.ts +74 -0
- package/dist/retry-manager.d.ts.map +1 -0
- package/dist/retry-manager.js +258 -0
- package/dist/retry-manager.js.map +1 -0
- package/dist/storage.d.ts +38 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +197 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { RetryOptions, RetryState, RetryManagerConfig, RetryResult, RetryMetrics } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Main retry manager with storage and memory protection
|
|
4
|
+
*/
|
|
5
|
+
export declare class RetryManager {
|
|
6
|
+
private config;
|
|
7
|
+
private storage;
|
|
8
|
+
private memoryProtection;
|
|
9
|
+
private metrics;
|
|
10
|
+
constructor(config?: Partial<RetryManagerConfig>);
|
|
11
|
+
/**
|
|
12
|
+
* Execute a function with retry logic and persistent state
|
|
13
|
+
*/
|
|
14
|
+
executeWithRetry<T>(id: string, fn: () => Promise<T>, options?: Partial<RetryOptions>): Promise<RetryResult<T>>;
|
|
15
|
+
/**
|
|
16
|
+
* Execute retry with backoff (original function from plans)
|
|
17
|
+
*/
|
|
18
|
+
retryWithBackoff<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Get retry state for a specific ID
|
|
21
|
+
*/
|
|
22
|
+
getRetryState(id: string): Promise<RetryState | null>;
|
|
23
|
+
/**
|
|
24
|
+
* List all retry states (optionally filtered by prefix)
|
|
25
|
+
*/
|
|
26
|
+
listRetryStates(prefix?: string): Promise<RetryState[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Cancel a retry operation
|
|
29
|
+
*/
|
|
30
|
+
cancelRetry(id: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Clear all retry states
|
|
33
|
+
*/
|
|
34
|
+
clearAll(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Get retry metrics
|
|
37
|
+
*/
|
|
38
|
+
getMetrics(): RetryMetrics;
|
|
39
|
+
/**
|
|
40
|
+
* Get memory protection stats
|
|
41
|
+
*/
|
|
42
|
+
getMemoryStats(): {
|
|
43
|
+
currentUsage: number;
|
|
44
|
+
maxUsage: number;
|
|
45
|
+
usagePercentage: number;
|
|
46
|
+
trend: number;
|
|
47
|
+
historySize: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Cleanup resources
|
|
51
|
+
*/
|
|
52
|
+
destroy(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Create initial retry state
|
|
55
|
+
*/
|
|
56
|
+
private createInitialState;
|
|
57
|
+
/**
|
|
58
|
+
* Calculate delay for next retry
|
|
59
|
+
*/
|
|
60
|
+
private calculateDelay;
|
|
61
|
+
/**
|
|
62
|
+
* Update metrics
|
|
63
|
+
*/
|
|
64
|
+
private updateMetrics;
|
|
65
|
+
/**
|
|
66
|
+
* Sleep utility
|
|
67
|
+
*/
|
|
68
|
+
private sleep;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Factory function to create a retry manager with default configuration
|
|
72
|
+
*/
|
|
73
|
+
export declare function createRetryManager(config?: Partial<RetryManagerConfig>): RetryManager;
|
|
74
|
+
//# sourceMappingURL=retry-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-manager.d.ts","sourceRoot":"","sources":["../src/retry-manager.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,YAAY,EACZ,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,YAAY,EAEb,MAAM,SAAS,CAAC;AAIjB;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,OAAO,CAMb;gBAEU,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAiBhD;;OAEG;IACG,gBAAgB,CAAC,CAAC,EACtB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC9B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IA4F1B;;OAEG;IACG,gBAAgB,CAAC,CAAC,EACtB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,CAAC,CAAC;IAuCb;;OAEG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAI3D;;OAEG;IACG,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAI7D;;OAEG;IACG,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;OAEG;IACH,UAAU,IAAI,YAAY;IAI1B;;OAEG;IACH,cAAc;;;;;;;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;IACH,OAAO,CAAC,aAAa;IAiBrB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG,YAAY,CAErF"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.RetryManager = void 0;
|
|
11
|
+
exports.createRetryManager = createRetryManager;
|
|
12
|
+
const memory_protection_1 = require("./memory-protection");
|
|
13
|
+
const storage_1 = require("./storage");
|
|
14
|
+
/**
|
|
15
|
+
* Main retry manager with storage and memory protection
|
|
16
|
+
*/
|
|
17
|
+
class RetryManager {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.metrics = {
|
|
20
|
+
totalRetries: 0,
|
|
21
|
+
successfulRetries: 0,
|
|
22
|
+
failedRetries: 0,
|
|
23
|
+
averageRetryTime: 0,
|
|
24
|
+
memoryUsage: 0
|
|
25
|
+
};
|
|
26
|
+
this.config = {
|
|
27
|
+
storage: config?.storage || (0, storage_1.createStorageAdapter)(),
|
|
28
|
+
memoryProtection: config?.memoryProtection || memory_protection_1.DEFAULT_MEMORY_PROTECTION_CONFIG,
|
|
29
|
+
defaultOptions: config?.defaultOptions || {
|
|
30
|
+
maxRetries: 5,
|
|
31
|
+
initialDelayMs: 1000,
|
|
32
|
+
maxDelayMs: 30000,
|
|
33
|
+
backoffFactor: 2,
|
|
34
|
+
jitter: true
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
this.storage = this.config.storage;
|
|
38
|
+
this.memoryProtection = new memory_protection_1.MemoryProtectionManager(this.config.memoryProtection);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Execute a function with retry logic and persistent state
|
|
42
|
+
*/
|
|
43
|
+
async executeWithRetry(id, fn, options) {
|
|
44
|
+
const startTime = Date.now();
|
|
45
|
+
const mergedOptions = {
|
|
46
|
+
maxRetries: 5,
|
|
47
|
+
initialDelayMs: 1000,
|
|
48
|
+
...this.config.defaultOptions,
|
|
49
|
+
...options
|
|
50
|
+
};
|
|
51
|
+
// Check memory protection
|
|
52
|
+
if (!this.memoryProtection.checkMemoryUsage()) {
|
|
53
|
+
throw new Error('Memory usage exceeded limits');
|
|
54
|
+
}
|
|
55
|
+
// Get existing state or create new one
|
|
56
|
+
let state = await this.storage.get(id) || this.createInitialState(id, mergedOptions);
|
|
57
|
+
// Check if operation was cancelled
|
|
58
|
+
if (state.status === 'failed' && state.error?.message === 'Retry cancelled') {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: state.error,
|
|
62
|
+
attempts: state.attempt,
|
|
63
|
+
totalTime: Date.now() - startTime
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const result = await fn();
|
|
68
|
+
// Success - update state and clean up
|
|
69
|
+
state.status = 'completed';
|
|
70
|
+
state.attempt = state.attempt + 1;
|
|
71
|
+
state.lastAttempt = new Date();
|
|
72
|
+
await this.storage.set(id, state);
|
|
73
|
+
const totalTime = Date.now() - startTime;
|
|
74
|
+
this.updateMetrics(true, totalTime);
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
data: result,
|
|
78
|
+
attempts: state.attempt,
|
|
79
|
+
totalTime
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
state.attempt = state.attempt + 1;
|
|
84
|
+
state.lastAttempt = new Date();
|
|
85
|
+
state.error = error;
|
|
86
|
+
if (state.attempt >= mergedOptions.maxRetries ||
|
|
87
|
+
(mergedOptions.shouldRetry && !mergedOptions.shouldRetry(error))) {
|
|
88
|
+
// Final failure
|
|
89
|
+
state.status = 'failed';
|
|
90
|
+
await this.storage.set(id, state);
|
|
91
|
+
const totalTime = Date.now() - startTime;
|
|
92
|
+
this.updateMetrics(false, totalTime);
|
|
93
|
+
if (mergedOptions.onFailure) {
|
|
94
|
+
mergedOptions.onFailure(error);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
success: false,
|
|
98
|
+
error,
|
|
99
|
+
attempts: state.attempt,
|
|
100
|
+
totalTime
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// Calculate next retry delay
|
|
104
|
+
const delay = this.calculateDelay(state.attempt, mergedOptions);
|
|
105
|
+
state.delay = delay;
|
|
106
|
+
state.nextRetry = new Date(Date.now() + delay);
|
|
107
|
+
state.status = 'retrying';
|
|
108
|
+
await this.storage.set(id, state);
|
|
109
|
+
if (mergedOptions.onRetry) {
|
|
110
|
+
mergedOptions.onRetry(state.attempt, delay, error);
|
|
111
|
+
}
|
|
112
|
+
// Wait for delay
|
|
113
|
+
await this.sleep(delay);
|
|
114
|
+
// Recursive retry
|
|
115
|
+
return this.executeWithRetry(id, fn, options);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Execute retry with backoff (original function from plans)
|
|
120
|
+
*/
|
|
121
|
+
async retryWithBackoff(fn, options) {
|
|
122
|
+
const { maxRetries, initialDelayMs, maxDelayMs = 10000, backoffFactor = 2, jitter = true, shouldRetry = () => true, onRetry, onFailure, } = options;
|
|
123
|
+
let attempt = 0;
|
|
124
|
+
let delay = initialDelayMs;
|
|
125
|
+
while (attempt < maxRetries) {
|
|
126
|
+
try {
|
|
127
|
+
return await fn();
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
attempt++;
|
|
131
|
+
if (attempt >= maxRetries || !shouldRetry(err)) {
|
|
132
|
+
if (onFailure)
|
|
133
|
+
onFailure(err);
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
let actualDelay = delay;
|
|
137
|
+
if (jitter) {
|
|
138
|
+
// Add random jitter: +/- 50%
|
|
139
|
+
const jitterAmount = Math.random() * delay * 0.5;
|
|
140
|
+
actualDelay = delay - delay * 0.25 + jitterAmount;
|
|
141
|
+
}
|
|
142
|
+
if (onRetry)
|
|
143
|
+
onRetry(attempt, actualDelay, err);
|
|
144
|
+
await this.sleep(actualDelay);
|
|
145
|
+
delay = Math.min(delay * backoffFactor, maxDelayMs);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Should never reach here
|
|
149
|
+
throw new Error('retryWithBackoff: Exceeded max retries');
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get retry state for a specific ID
|
|
153
|
+
*/
|
|
154
|
+
async getRetryState(id) {
|
|
155
|
+
return this.storage.get(id);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* List all retry states (optionally filtered by prefix)
|
|
159
|
+
*/
|
|
160
|
+
async listRetryStates(prefix) {
|
|
161
|
+
return this.storage.list(prefix);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Cancel a retry operation
|
|
165
|
+
*/
|
|
166
|
+
async cancelRetry(id) {
|
|
167
|
+
const state = await this.storage.get(id);
|
|
168
|
+
if (state && (state.status === 'retrying' || state.status === 'pending')) {
|
|
169
|
+
state.status = 'failed';
|
|
170
|
+
state.error = new Error('Retry cancelled');
|
|
171
|
+
await this.storage.set(id, state);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Clear all retry states
|
|
176
|
+
*/
|
|
177
|
+
async clearAll() {
|
|
178
|
+
await this.storage.clear();
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get retry metrics
|
|
182
|
+
*/
|
|
183
|
+
getMetrics() {
|
|
184
|
+
return { ...this.metrics };
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get memory protection stats
|
|
188
|
+
*/
|
|
189
|
+
getMemoryStats() {
|
|
190
|
+
return this.memoryProtection.getStats();
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Cleanup resources
|
|
194
|
+
*/
|
|
195
|
+
destroy() {
|
|
196
|
+
this.memoryProtection.destroy();
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Create initial retry state
|
|
200
|
+
*/
|
|
201
|
+
createInitialState(id, options) {
|
|
202
|
+
return {
|
|
203
|
+
id,
|
|
204
|
+
attempt: 0,
|
|
205
|
+
lastAttempt: new Date(),
|
|
206
|
+
nextRetry: new Date(),
|
|
207
|
+
delay: options.initialDelayMs,
|
|
208
|
+
maxRetries: options.maxRetries,
|
|
209
|
+
status: 'pending',
|
|
210
|
+
metadata: {}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Calculate delay for next retry
|
|
215
|
+
*/
|
|
216
|
+
calculateDelay(attempt, options) {
|
|
217
|
+
let delay = options.initialDelayMs * Math.pow(options.backoffFactor || 2, attempt - 1);
|
|
218
|
+
if (options.maxDelayMs) {
|
|
219
|
+
delay = Math.min(delay, options.maxDelayMs);
|
|
220
|
+
}
|
|
221
|
+
if (options.jitter) {
|
|
222
|
+
const jitterAmount = Math.random() * delay * 0.5;
|
|
223
|
+
delay = delay - delay * 0.25 + jitterAmount;
|
|
224
|
+
}
|
|
225
|
+
return delay;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Update metrics
|
|
229
|
+
*/
|
|
230
|
+
updateMetrics(success, duration) {
|
|
231
|
+
this.metrics.totalRetries++;
|
|
232
|
+
if (success) {
|
|
233
|
+
this.metrics.successfulRetries++;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
this.metrics.failedRetries++;
|
|
237
|
+
}
|
|
238
|
+
// Update average retry time
|
|
239
|
+
const totalTime = this.metrics.averageRetryTime * (this.metrics.totalRetries - 1) + duration;
|
|
240
|
+
this.metrics.averageRetryTime = totalTime / this.metrics.totalRetries;
|
|
241
|
+
// Update memory usage
|
|
242
|
+
this.metrics.memoryUsage = this.memoryProtection.getStats().currentUsage;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Sleep utility
|
|
246
|
+
*/
|
|
247
|
+
sleep(ms) {
|
|
248
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
exports.RetryManager = RetryManager;
|
|
252
|
+
/**
|
|
253
|
+
* Factory function to create a retry manager with default configuration
|
|
254
|
+
*/
|
|
255
|
+
function createRetryManager(config) {
|
|
256
|
+
return new RetryManager(config);
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=retry-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-manager.js","sourceRoot":"","sources":["../src/retry-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StorageAdapter, RetryState } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory storage adapter with LRU eviction
|
|
4
|
+
*/
|
|
5
|
+
export declare class MemoryStorageAdapter implements StorageAdapter {
|
|
6
|
+
private storage;
|
|
7
|
+
private maxSize;
|
|
8
|
+
private accessOrder;
|
|
9
|
+
constructor(maxSize?: number);
|
|
10
|
+
get(id: string): Promise<RetryState | null>;
|
|
11
|
+
set(id: string, state: RetryState): Promise<void>;
|
|
12
|
+
delete(id: string): Promise<void>;
|
|
13
|
+
list(prefix?: string): Promise<RetryState[]>;
|
|
14
|
+
clear(): Promise<void>;
|
|
15
|
+
private updateAccessOrder;
|
|
16
|
+
private evictOldest;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Redis storage adapter with fallback to memory
|
|
20
|
+
*/
|
|
21
|
+
export declare class RedisStorageAdapter implements StorageAdapter {
|
|
22
|
+
private redis;
|
|
23
|
+
private memoryFallback;
|
|
24
|
+
private useFallback;
|
|
25
|
+
private prefix;
|
|
26
|
+
constructor(redisClient?: any, prefix?: string);
|
|
27
|
+
private getKey;
|
|
28
|
+
get(id: string): Promise<RetryState | null>;
|
|
29
|
+
set(id: string, state: RetryState): Promise<void>;
|
|
30
|
+
delete(id: string): Promise<void>;
|
|
31
|
+
list(prefix?: string): Promise<RetryState[]>;
|
|
32
|
+
clear(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Factory function to create appropriate storage adapter based on environment
|
|
36
|
+
*/
|
|
37
|
+
export declare function createStorageAdapter(): StorageAdapter;
|
|
38
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErD;;GAEG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;gBAEvB,OAAO,GAAE,MAAa;IAI5B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAS3C,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAU5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,WAAW;CAMpB;AAED;;GAEG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,CAAC,EAAE,GAAG,EAAE,MAAM,GAAE,MAAiB;IAMxD,OAAO,CAAC,MAAM;IAIR,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAqB3C,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAejD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IA2B5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAgB7B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAmBrD"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.RedisStorageAdapter = exports.MemoryStorageAdapter = void 0;
|
|
11
|
+
exports.createStorageAdapter = createStorageAdapter;
|
|
12
|
+
/**
|
|
13
|
+
* In-memory storage adapter with LRU eviction
|
|
14
|
+
*/
|
|
15
|
+
class MemoryStorageAdapter {
|
|
16
|
+
constructor(maxSize = 1000) {
|
|
17
|
+
this.storage = new Map();
|
|
18
|
+
this.accessOrder = [];
|
|
19
|
+
this.maxSize = maxSize;
|
|
20
|
+
}
|
|
21
|
+
async get(id) {
|
|
22
|
+
const state = this.storage.get(id);
|
|
23
|
+
if (state) {
|
|
24
|
+
// Update access order for LRU
|
|
25
|
+
this.updateAccessOrder(id);
|
|
26
|
+
}
|
|
27
|
+
return state || null;
|
|
28
|
+
}
|
|
29
|
+
async set(id, state) {
|
|
30
|
+
if (this.storage.size >= this.maxSize) {
|
|
31
|
+
this.evictOldest();
|
|
32
|
+
}
|
|
33
|
+
this.storage.set(id, state);
|
|
34
|
+
this.updateAccessOrder(id);
|
|
35
|
+
}
|
|
36
|
+
async delete(id) {
|
|
37
|
+
this.storage.delete(id);
|
|
38
|
+
const index = this.accessOrder.indexOf(id);
|
|
39
|
+
if (index > -1) {
|
|
40
|
+
this.accessOrder.splice(index, 1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async list(prefix) {
|
|
44
|
+
const states = [];
|
|
45
|
+
for (const [id, state] of this.storage.entries()) {
|
|
46
|
+
if (!prefix || id.startsWith(prefix)) {
|
|
47
|
+
states.push(state);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return states;
|
|
51
|
+
}
|
|
52
|
+
async clear() {
|
|
53
|
+
this.storage.clear();
|
|
54
|
+
this.accessOrder = [];
|
|
55
|
+
}
|
|
56
|
+
updateAccessOrder(id) {
|
|
57
|
+
const index = this.accessOrder.indexOf(id);
|
|
58
|
+
if (index > -1) {
|
|
59
|
+
this.accessOrder.splice(index, 1);
|
|
60
|
+
}
|
|
61
|
+
this.accessOrder.push(id);
|
|
62
|
+
}
|
|
63
|
+
evictOldest() {
|
|
64
|
+
if (this.accessOrder.length > 0) {
|
|
65
|
+
const oldestId = this.accessOrder.shift();
|
|
66
|
+
this.storage.delete(oldestId);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.MemoryStorageAdapter = MemoryStorageAdapter;
|
|
71
|
+
/**
|
|
72
|
+
* Redis storage adapter with fallback to memory
|
|
73
|
+
*/
|
|
74
|
+
class RedisStorageAdapter {
|
|
75
|
+
constructor(redisClient, prefix = 'retry:') {
|
|
76
|
+
this.useFallback = false;
|
|
77
|
+
this.redis = redisClient;
|
|
78
|
+
this.memoryFallback = new MemoryStorageAdapter();
|
|
79
|
+
this.prefix = prefix;
|
|
80
|
+
}
|
|
81
|
+
getKey(id) {
|
|
82
|
+
return `${this.prefix}${id}`;
|
|
83
|
+
}
|
|
84
|
+
async get(id) {
|
|
85
|
+
if (this.useFallback || !this.redis) {
|
|
86
|
+
return this.memoryFallback.get(id);
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const data = await this.redis.get(this.getKey(id));
|
|
90
|
+
if (!data)
|
|
91
|
+
return null;
|
|
92
|
+
const state = JSON.parse(data);
|
|
93
|
+
// Convert date strings back to Date objects
|
|
94
|
+
state.lastAttempt = new Date(state.lastAttempt);
|
|
95
|
+
state.nextRetry = new Date(state.nextRetry);
|
|
96
|
+
return state;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.warn('Redis get failed, falling back to memory:', error);
|
|
100
|
+
this.useFallback = true;
|
|
101
|
+
return this.memoryFallback.get(id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async set(id, state) {
|
|
105
|
+
if (this.useFallback || !this.redis) {
|
|
106
|
+
return this.memoryFallback.set(id, state);
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const serialized = JSON.stringify(state);
|
|
110
|
+
await this.redis.set(this.getKey(id), serialized, 'EX', 3600); // 1 hour TTL
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.warn('Redis set failed, falling back to memory:', error);
|
|
114
|
+
this.useFallback = true;
|
|
115
|
+
return this.memoryFallback.set(id, state);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async delete(id) {
|
|
119
|
+
if (this.useFallback || !this.redis) {
|
|
120
|
+
return this.memoryFallback.delete(id);
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
await this.redis.del(this.getKey(id));
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.warn('Redis delete failed, falling back to memory:', error);
|
|
127
|
+
this.useFallback = true;
|
|
128
|
+
return this.memoryFallback.delete(id);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async list(prefix) {
|
|
132
|
+
if (this.useFallback || !this.redis) {
|
|
133
|
+
return this.memoryFallback.list(prefix);
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const pattern = prefix ? `${this.prefix}${prefix}*` : `${this.prefix}*`;
|
|
137
|
+
const keys = await this.redis.keys(pattern);
|
|
138
|
+
const states = [];
|
|
139
|
+
for (const key of keys) {
|
|
140
|
+
const data = await this.redis.get(key);
|
|
141
|
+
if (data) {
|
|
142
|
+
const state = JSON.parse(data);
|
|
143
|
+
state.lastAttempt = new Date(state.lastAttempt);
|
|
144
|
+
state.nextRetry = new Date(state.nextRetry);
|
|
145
|
+
states.push(state);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return states;
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.warn('Redis list failed, falling back to memory:', error);
|
|
152
|
+
this.useFallback = true;
|
|
153
|
+
return this.memoryFallback.list(prefix);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async clear() {
|
|
157
|
+
if (this.useFallback || !this.redis) {
|
|
158
|
+
return this.memoryFallback.clear();
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const keys = await this.redis.keys(`${this.prefix}*`);
|
|
162
|
+
if (keys.length > 0) {
|
|
163
|
+
await this.redis.del(...keys);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.warn('Redis clear failed, falling back to memory:', error);
|
|
168
|
+
this.useFallback = true;
|
|
169
|
+
return this.memoryFallback.clear();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.RedisStorageAdapter = RedisStorageAdapter;
|
|
174
|
+
/**
|
|
175
|
+
* Factory function to create appropriate storage adapter based on environment
|
|
176
|
+
*/
|
|
177
|
+
function createStorageAdapter() {
|
|
178
|
+
const storageType = process.env.RETRY_STORAGE_TYPE || 'memory';
|
|
179
|
+
switch (storageType.toLowerCase()) {
|
|
180
|
+
case 'redis':
|
|
181
|
+
try {
|
|
182
|
+
const redis = require('redis');
|
|
183
|
+
const client = redis.createClient({
|
|
184
|
+
url: process.env.REDIS_URL || 'redis://localhost:6379'
|
|
185
|
+
});
|
|
186
|
+
return new RedisStorageAdapter(client);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
console.warn('Redis not available, falling back to memory storage');
|
|
190
|
+
return new MemoryStorageAdapter();
|
|
191
|
+
}
|
|
192
|
+
case 'memory':
|
|
193
|
+
default:
|
|
194
|
+
return new MemoryStorageAdapter();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface RetryOptions {
|
|
2
|
+
maxRetries: number;
|
|
3
|
+
initialDelayMs: number;
|
|
4
|
+
maxDelayMs?: number;
|
|
5
|
+
backoffFactor?: number;
|
|
6
|
+
jitter?: boolean;
|
|
7
|
+
shouldRetry?: (err: any) => boolean;
|
|
8
|
+
onRetry?: (attempt: number, delay: number, err: any) => void;
|
|
9
|
+
onFailure?: (err: any) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface RetryState {
|
|
12
|
+
id: string;
|
|
13
|
+
attempt: number;
|
|
14
|
+
lastAttempt: Date;
|
|
15
|
+
nextRetry: Date;
|
|
16
|
+
delay: number;
|
|
17
|
+
maxRetries: number;
|
|
18
|
+
status: 'pending' | 'retrying' | 'completed' | 'failed';
|
|
19
|
+
error?: any;
|
|
20
|
+
metadata?: Record<string, any>;
|
|
21
|
+
}
|
|
22
|
+
export interface StorageAdapter {
|
|
23
|
+
get(id: string): Promise<RetryState | null>;
|
|
24
|
+
set(id: string, state: RetryState): Promise<void>;
|
|
25
|
+
delete(id: string): Promise<void>;
|
|
26
|
+
list(prefix?: string): Promise<RetryState[]>;
|
|
27
|
+
clear(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export interface MemoryProtectionConfig {
|
|
30
|
+
maxMemoryUsage: number;
|
|
31
|
+
maxRetryStates: number;
|
|
32
|
+
cleanupInterval: number;
|
|
33
|
+
evictionPolicy: 'lru' | 'fifo' | 'random';
|
|
34
|
+
}
|
|
35
|
+
export interface RetryManagerConfig {
|
|
36
|
+
storage: StorageAdapter;
|
|
37
|
+
memoryProtection?: MemoryProtectionConfig;
|
|
38
|
+
defaultOptions?: Partial<RetryOptions>;
|
|
39
|
+
}
|
|
40
|
+
export interface RetryResult<T> {
|
|
41
|
+
success: boolean;
|
|
42
|
+
data?: T;
|
|
43
|
+
error?: any;
|
|
44
|
+
attempts: number;
|
|
45
|
+
totalTime: number;
|
|
46
|
+
}
|
|
47
|
+
export interface RetryMetrics {
|
|
48
|
+
totalRetries: number;
|
|
49
|
+
successfulRetries: number;
|
|
50
|
+
failedRetries: number;
|
|
51
|
+
averageRetryTime: number;
|
|
52
|
+
memoryUsage: number;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC5C,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;EAME"}
|