0
# Error Handling
1
2
Comprehensive error handling system with custom error handlers, error wrapping, and selective error processing for fine-grained control over error management in promise pools.
3
4
## Capabilities
5
6
### Custom Error Handler
7
8
Set a custom error handler to process errors selectively instead of collecting them automatically.
9
10
```typescript { .api }
11
/**
12
* Set a custom error handler function
13
* @param handler - Function to handle errors, or undefined to disable
14
* @returns PromisePool instance for chaining
15
*/
16
handleError(handler: ErrorHandler<T>): PromisePool<T>;
17
18
type ErrorHandler<T> = (
19
error: Error,
20
item: T,
21
pool: Stoppable & UsesConcurrency
22
) => Promise<void> | void;
23
```
24
25
**Key Behaviors:**
26
- When a custom error handler is provided, the pool does **not** automatically collect errors
27
- You must collect errors yourself within the handler
28
- Throwing an error from the handler will immediately stop the pool
29
- Returning normally allows processing to continue
30
31
**Usage Examples:**
32
33
```typescript
34
import { PromisePool } from "@supercharge/promise-pool";
35
36
// Collect specific errors, rethrow others
37
const collectedErrors = [];
38
39
try {
40
const { results } = await PromisePool
41
.for(users)
42
.withConcurrency(4)
43
.handleError(async (error, user, pool) => {
44
if (error instanceof ValidationError) {
45
collectedErrors.push({ error, user });
46
return; // Continue processing
47
}
48
49
if (error instanceof ThrottleError) {
50
await retryUser(user); // Custom retry logic
51
return;
52
}
53
54
// Uncaught errors will immediately stop the pool
55
throw error;
56
})
57
.process(async (user) => {
58
return await processUser(user);
59
});
60
61
await handleCollectedErrors(collectedErrors);
62
} catch (error) {
63
await handleCriticalError(error);
64
}
65
66
// Stop pool on critical errors
67
const { results } = await PromisePool
68
.for(items)
69
.handleError(async (error, item, pool) => {
70
if (error instanceof CriticalError) {
71
pool.stop(); // Stop processing remaining items
72
return;
73
}
74
75
console.warn(`Non-critical error for item ${item}:`, error.message);
76
})
77
.process(async (item) => processItem(item));
78
```
79
80
### PromisePoolError Class
81
82
Wrapper class that provides context about which item caused an error.
83
84
```typescript { .api }
85
/**
86
* Error wrapper that includes the item that caused the error
87
*/
88
class PromisePoolError<T, E = any> extends Error {
89
/** The item that caused this error */
90
item: T;
91
/** The original, raw error instance */
92
raw: E;
93
94
constructor(error: E, item: T);
95
96
/**
97
* Create a new promise pool error instance wrapping the error and item
98
* @param error - The original error
99
* @param item - The item that caused the error
100
* @returns New PromisePoolError instance
101
*/
102
static createFrom<T, E = any>(error: E, item: T): PromisePoolError<T>;
103
}
104
```
105
106
**Usage Examples:**
107
108
```typescript
109
// Without custom error handler (default behavior)
110
const { results, errors } = await PromisePool
111
.for(users)
112
.process(async (user) => {
113
if (!user.email) {
114
throw new Error("Email is required");
115
}
116
return await processUser(user);
117
});
118
119
// Handle collected errors
120
errors.forEach(poolError => {
121
console.log(`Error processing user ${poolError.item.name}:`);
122
console.log(` Original error: ${poolError.raw.message}`);
123
console.log(` Item data:`, poolError.item);
124
});
125
126
// Create custom PromisePoolError
127
try {
128
await processItem(item);
129
} catch (error) {
130
const poolError = PromisePoolError.createFrom(error, item);
131
throw poolError;
132
}
133
```
134
135
### ValidationError Class
136
137
Error class specifically for validation failures in pool configuration.
138
139
```typescript { .api }
140
/**
141
* Error class for validation failures
142
*/
143
class ValidationError extends Error {
144
constructor(message?: string);
145
146
/**
147
* Create a validation error with the given message
148
* @param message - Error message
149
* @returns New ValidationError instance
150
*/
151
static createFrom(message: string): ValidationError;
152
}
153
```
154
155
Validation errors are thrown for:
156
- Invalid concurrency values (must be number >= 1)
157
- Invalid timeout values (must be number >= 0 or undefined)
158
- Invalid items (must be array, iterable, or async iterable)
159
- Invalid handler functions
160
161
**Usage Examples:**
162
163
```typescript
164
try {
165
await PromisePool
166
.withConcurrency(-1) // Invalid: must be >= 1
167
.for(items)
168
.process(async (item) => item);
169
} catch (error) {
170
if (error instanceof ValidationError) {
171
console.log("Configuration error:", error.message);
172
// Handle validation error
173
}
174
}
175
```
176
177
### StopThePromisePoolError Class
178
179
Special error class used internally when the pool is stopped manually.
180
181
```typescript { .api }
182
/**
183
* Special error class for stopping pool execution
184
*/
185
class StopThePromisePoolError extends Error {
186
constructor();
187
}
188
```
189
190
This error is thrown internally when `pool.stop()` is called and should not typically be handled directly by user code.
191
192
## Error Handling Patterns
193
194
### Pattern 1: Default Error Collection
195
196
The simplest approach - let the pool collect all errors automatically.
197
198
```typescript
199
const { results, errors } = await PromisePool
200
.for(items)
201
.process(async (item) => {
202
// Any thrown errors are automatically collected
203
return await processItem(item);
204
});
205
206
if (errors.length > 0) {
207
console.log(`${errors.length} errors occurred`);
208
errors.forEach(error => {
209
console.log(`Item: ${error.item}, Error: ${error.message}`);
210
});
211
}
212
```
213
214
### Pattern 2: Selective Error Handling
215
216
Handle specific error types differently while collecting others.
217
218
```typescript
219
const collectedErrors = [];
220
221
const { results } = await PromisePool
222
.for(items)
223
.handleError(async (error, item, pool) => {
224
if (error instanceof NetworkError) {
225
// Retry network errors
226
await retryWithBackoff(() => processItem(item));
227
return;
228
}
229
230
if (error instanceof ValidationError) {
231
// Collect validation errors for later processing
232
collectedErrors.push({ error, item });
233
return;
234
}
235
236
// Rethrow unknown errors to stop the pool
237
throw error;
238
})
239
.process(async (item) => processItem(item));
240
```
241
242
### Pattern 3: Early Termination on Critical Errors
243
244
Stop processing when critical errors occur.
245
246
```typescript
247
const { results } = await PromisePool
248
.for(items)
249
.handleError(async (error, item, pool) => {
250
if (error instanceof DatabaseConnectionError) {
251
console.error("Database connection lost, stopping pool");
252
pool.stop();
253
return;
254
}
255
256
// Log non-critical errors but continue processing
257
console.warn(`Non-critical error for item ${item}:`, error.message);
258
})
259
.process(async (item) => processItem(item));
260
```
261
262
### Pattern 4: Error Recovery and State Management
263
264
Advanced error handling with recovery mechanisms.
265
266
```typescript
267
const retryCount = new Map();
268
const maxRetries = 3;
269
270
const { results } = await PromisePool
271
.for(items)
272
.handleError(async (error, item, pool) => {
273
const currentRetries = retryCount.get(item) || 0;
274
275
if (currentRetries < maxRetries && isRetryableError(error)) {
276
retryCount.set(item, currentRetries + 1);
277
278
// Add item back to processing queue (pseudo-code)
279
// In practice, you might need to track failed items separately
280
console.log(`Retrying item ${item} (attempt ${currentRetries + 1})`);
281
return;
282
}
283
284
// Max retries reached or non-retryable error
285
console.error(`Failed to process item ${item} after ${maxRetries} attempts`);
286
})
287
.process(async (item) => processItem(item));
288
```