or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-pool-management.mderror-handling.mdindex.mdpool-control.mdprogress-tracking.md

error-handling.mddocs/

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

```