@backendkit-labs/bulkhead 0.1.2 → 0.2.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/README.md +338 -337
- package/dist/{chunk-LXXCDKHB.cjs → chunk-2HCEIIKT.cjs} +16 -9
- package/dist/chunk-2HCEIIKT.cjs.map +1 -0
- package/dist/{chunk-SRWDZPTJ.js → chunk-OROUPJGG.js} +16 -9
- package/dist/chunk-OROUPJGG.js.map +1 -0
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/nestjs/index.cjs +21 -25
- package/dist/nestjs/index.cjs.map +1 -1
- package/dist/nestjs/index.js +5 -9
- package/dist/nestjs/index.js.map +1 -1
- package/package.json +103 -103
- package/dist/chunk-LXXCDKHB.cjs.map +0 -1
- package/dist/chunk-SRWDZPTJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,337 +1,338 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@backendkit-labs/bulkhead)
|
|
4
|
-
[](LICENSE)
|
|
6
|
-
[](package.json)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
registry.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
@
|
|
226
|
-
@
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
@
|
|
232
|
-
@
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
@
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
| `
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
1
|
+
# @backendkit-labs/bulkhead
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@backendkit-labs/bulkhead)
|
|
4
|
+
[](https://github.com/BackendKit-labs/backendkit-monorepo/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](package.json)
|
|
7
|
+
[](https://backendkitlabs.dev/docs/bulkhead/)
|
|
8
|
+
|
|
9
|
+
> Bulkhead concurrency limiting for Node.js — inspired by Resilience4j. Framework-agnostic core with optional NestJS integration.
|
|
10
|
+
|
|
11
|
+
Prevents resource exhaustion and cascading failures by limiting how many operations run simultaneously on a given resource.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @backendkit-labs/bulkhead
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## TypeScript Configuration
|
|
24
|
+
|
|
25
|
+
### Subpath exports (`/nestjs`)
|
|
26
|
+
|
|
27
|
+
This package uses the `exports` field in `package.json` to expose the `/nestjs` subpath. TypeScript's ability to resolve it depends on the `moduleResolution` setting in your `tsconfig.json`.
|
|
28
|
+
|
|
29
|
+
**Modern resolution (recommended) — no extra config needed:**
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"compilerOptions": {
|
|
34
|
+
"moduleResolution": "bundler"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`"bundler"`, `"node16"`, and `"nodenext"` all understand the `exports` field natively. This is the recommended setting for any project using a bundler or NestJS on TypeScript ≥ 5.
|
|
40
|
+
|
|
41
|
+
**Legacy resolution (`"node"`) — add a `paths` alias:**
|
|
42
|
+
|
|
43
|
+
NestJS projects generated before ~2024 default to `"moduleResolution": "node"`, which ignores the `exports` field. Add an explicit alias so TypeScript can find the types:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"compilerOptions": {
|
|
48
|
+
"moduleResolution": "node",
|
|
49
|
+
"paths": {
|
|
50
|
+
"@backendkit-labs/bulkhead/nestjs": [
|
|
51
|
+
"./node_modules/@backendkit-labs/bulkhead/dist/nestjs/index"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> **Why?** The `"node"` resolver was designed before subpath exports existed and only reads `main`/`types` at the package root — it ignores the `exports` map entirely. The `paths` alias manually points TypeScript to the correct `.d.ts` file.
|
|
59
|
+
|
|
60
|
+
### NestJS decorator support
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"compilerOptions": {
|
|
65
|
+
"experimentalDecorators": true,
|
|
66
|
+
"emitDecoratorMetadata": true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
And import `reflect-metadata` once at application startup:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// main.ts
|
|
75
|
+
import 'reflect-metadata';
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> NestJS CLI scaffolds these automatically. You only need to verify them if setting up a project manually.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Quick Start — Framework-agnostic
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { Bulkhead } from '@backendkit-labs/bulkhead';
|
|
86
|
+
|
|
87
|
+
const bulkhead = new Bulkhead({
|
|
88
|
+
name: 'payments',
|
|
89
|
+
maxConcurrentCalls: 10,
|
|
90
|
+
maxQueueSize: 50,
|
|
91
|
+
queueTimeoutMs: 5000,
|
|
92
|
+
rejectWhenFull: true,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const result = await bulkhead.execute(() => callPaymentApi());
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Core API
|
|
101
|
+
|
|
102
|
+
### `Bulkhead`
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const bulkhead = new Bulkhead(config);
|
|
106
|
+
|
|
107
|
+
// Execute a task — waits in queue if at capacity
|
|
108
|
+
await bulkhead.execute(async () => { ... });
|
|
109
|
+
|
|
110
|
+
// Check if capacity is available before executing
|
|
111
|
+
if (bulkhead.canAccept()) { ... }
|
|
112
|
+
|
|
113
|
+
// Current metrics snapshot
|
|
114
|
+
const metrics = bulkhead.getMetrics();
|
|
115
|
+
|
|
116
|
+
// Reset all counters
|
|
117
|
+
bulkhead.resetMetrics();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `BulkheadConfig`
|
|
121
|
+
|
|
122
|
+
| Property | Type | Description |
|
|
123
|
+
|----------|------|-------------|
|
|
124
|
+
| `name` | `string` | Identifier for metrics and error messages |
|
|
125
|
+
| `maxConcurrentCalls` | `number` | Max simultaneous executions |
|
|
126
|
+
| `maxQueueSize` | `number` | Max tasks waiting in queue |
|
|
127
|
+
| `queueTimeoutMs` | `number` | Max time a task can wait in queue (ms) |
|
|
128
|
+
| `rejectWhenFull` | `boolean` | Throw immediately when full; if `false`, retries with exponential backoff |
|
|
129
|
+
|
|
130
|
+
### `BulkheadMetrics`
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
{
|
|
134
|
+
name: string;
|
|
135
|
+
activeCalls: number;
|
|
136
|
+
queuedCalls: number;
|
|
137
|
+
maxConcurrentCalls: number;
|
|
138
|
+
maxQueueSize: number;
|
|
139
|
+
totalCalls: number;
|
|
140
|
+
successfulCalls: number;
|
|
141
|
+
failedCalls: number;
|
|
142
|
+
rejectedCalls: number;
|
|
143
|
+
timedOutCalls: number;
|
|
144
|
+
averageDurationMs: number;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Errors
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { BulkheadRejectedError, BulkheadTimeoutError } from '@backendkit-labs/bulkhead';
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
await bulkhead.execute(task);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (error instanceof BulkheadRejectedError) {
|
|
157
|
+
// Queue was full — task was not queued
|
|
158
|
+
}
|
|
159
|
+
if (error instanceof BulkheadTimeoutError) {
|
|
160
|
+
// Task waited too long in queue
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## BulkheadRegistry
|
|
168
|
+
|
|
169
|
+
Manages named bulkhead instances with sensible defaults for common resource types:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { BulkheadRegistry } from '@backendkit-labs/bulkhead';
|
|
173
|
+
|
|
174
|
+
const registry = new BulkheadRegistry();
|
|
175
|
+
|
|
176
|
+
// Custom
|
|
177
|
+
const bh = registry.getOrCreate({ name: 'my-service', maxConcurrentCalls: 15 });
|
|
178
|
+
|
|
179
|
+
// Pre-configured factory methods
|
|
180
|
+
const clientBh = registry.getForClient('client-123', '/api/orders'); // 5 concurrent, 20 queued
|
|
181
|
+
const serviceBh = registry.getForService('inventory-service'); // 20 concurrent, 200 queued
|
|
182
|
+
const dbBh = registry.getForDatabase('orders_schema'); // 15 concurrent, 150 queued
|
|
183
|
+
const externalBh = registry.getForHttpExternal('stripe-api'); // 8 concurrent, 50 queued, 10s timeout
|
|
184
|
+
|
|
185
|
+
// Observability
|
|
186
|
+
const all = registry.getAllMetrics();
|
|
187
|
+
const overloaded = registry.getOverloadedBulkheads(); // ≥80% active capacity
|
|
188
|
+
registry.resetAllMetrics();
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
| Method | Concurrent | Queue | Timeout |
|
|
192
|
+
|--------|-----------|-------|---------|
|
|
193
|
+
| `getForClient(id, endpoint?)` | 5 | 20 | 30s |
|
|
194
|
+
| `getForService(name)` | 20 | 200 | 30s |
|
|
195
|
+
| `getForDatabase(schema)` | 15 | 150 | 30s |
|
|
196
|
+
| `getForHttpExternal(name)` | 8 | 50 | 10s |
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## NestJS Integration
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
npm install @backendkit-labs/bulkhead
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Import `BulkheadModule` into your NestJS application:
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { BulkheadModule } from '@backendkit-labs/bulkhead/nestjs';
|
|
210
|
+
|
|
211
|
+
@Module({
|
|
212
|
+
imports: [BulkheadModule],
|
|
213
|
+
})
|
|
214
|
+
export class AppModule {}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Guard — declarative per-route protection
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import { UseBulkhead, BulkheadGuard } from '@backendkit-labs/bulkhead/nestjs';
|
|
221
|
+
|
|
222
|
+
@Controller('orders')
|
|
223
|
+
export class OrdersController {
|
|
224
|
+
// Shared service-level limit
|
|
225
|
+
@UseBulkhead({ name: 'orders-service' })
|
|
226
|
+
@UseGuards(BulkheadGuard)
|
|
227
|
+
@Get()
|
|
228
|
+
findAll() { ... }
|
|
229
|
+
|
|
230
|
+
// Per-client isolation (reads x-client-id header)
|
|
231
|
+
@UseBulkhead({ name: 'orders-create', perClient: true })
|
|
232
|
+
@UseGuards(BulkheadGuard)
|
|
233
|
+
@Post()
|
|
234
|
+
create() { ... }
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Returns `503 Service Unavailable` when at capacity.
|
|
239
|
+
|
|
240
|
+
### Interceptor — wraps handler execution inside the bulkhead
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import { BulkheadInterceptor } from '@backendkit-labs/bulkhead/nestjs';
|
|
244
|
+
|
|
245
|
+
// Apply globally
|
|
246
|
+
app.useGlobalInterceptors(new BulkheadInterceptor(registry));
|
|
247
|
+
|
|
248
|
+
// Or per controller / route
|
|
249
|
+
@UseInterceptors(BulkheadInterceptor)
|
|
250
|
+
@Controller('reports')
|
|
251
|
+
export class ReportsController { ... }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Returns `503` on rejection, `408` on timeout.
|
|
255
|
+
|
|
256
|
+
### Middleware — global HTTP concurrency limit
|
|
257
|
+
|
|
258
|
+
Protects the entire service from being overwhelmed before requests even reach your handlers:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { HttpBulkheadMiddleware } from '@backendkit-labs/bulkhead/nestjs';
|
|
262
|
+
|
|
263
|
+
@Module({ imports: [BulkheadModule] })
|
|
264
|
+
export class AppModule implements NestModule {
|
|
265
|
+
configure(consumer: MiddlewareConsumer) {
|
|
266
|
+
consumer.apply(HttpBulkheadMiddleware).forRoutes('*');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Configure via environment variables:
|
|
272
|
+
|
|
273
|
+
| Variable | Default | Description |
|
|
274
|
+
|----------|---------|-------------|
|
|
275
|
+
| `HTTP_BULKHEAD_CONCURRENCY` | `50` | Max concurrent requests |
|
|
276
|
+
| `HTTP_BULKHEAD_MAX_QUEUE` | `100` | Max queued requests |
|
|
277
|
+
|
|
278
|
+
Returns `429 Too Many Requests` when the queue is full.
|
|
279
|
+
|
|
280
|
+
### Method Decorator
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { WithBulkhead } from '@backendkit-labs/bulkhead/nestjs';
|
|
284
|
+
|
|
285
|
+
@Injectable()
|
|
286
|
+
export class ReportService {
|
|
287
|
+
// Must have bulkheadRegistry injected
|
|
288
|
+
constructor(public readonly bulkheadRegistry: BulkheadRegistry) {}
|
|
289
|
+
|
|
290
|
+
@WithBulkhead({ name: 'report-generation', maxConcurrent: 3 })
|
|
291
|
+
async generateReport(id: string) { ... }
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Monitoring — BulkheadService
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { BulkheadService } from '@backendkit-labs/bulkhead/nestjs';
|
|
299
|
+
|
|
300
|
+
@Controller('health')
|
|
301
|
+
export class HealthController {
|
|
302
|
+
constructor(private readonly bulkheads: BulkheadService) {}
|
|
303
|
+
|
|
304
|
+
@Get('bulkheads')
|
|
305
|
+
getMetrics() {
|
|
306
|
+
return {
|
|
307
|
+
all: this.bulkheads.getAllMetrics(),
|
|
308
|
+
critical: this.bulkheads.getCriticalBulkheads(), // ≥90% active
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
`BulkheadService` also logs a warning every 60 seconds when any bulkhead reaches 90%+ utilization.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Architecture
|
|
319
|
+
|
|
320
|
+
```
|
|
321
|
+
@backendkit-labs/bulkhead (core — no framework deps)
|
|
322
|
+
Bulkhead queue-based concurrency limiter
|
|
323
|
+
BulkheadRegistry named instances + factory methods
|
|
324
|
+
|
|
325
|
+
@backendkit-labs/bulkhead/nestjs (optional NestJS layer)
|
|
326
|
+
BulkheadModule NestJS module
|
|
327
|
+
BulkheadGuard @UseBulkhead() per-route decorator
|
|
328
|
+
BulkheadInterceptor wraps handler in execute()
|
|
329
|
+
HttpBulkheadMiddleware global HTTP request limiter
|
|
330
|
+
WithBulkhead method-level decorator
|
|
331
|
+
BulkheadService metrics + auto-monitoring
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## License
|
|
337
|
+
|
|
338
|
+
Apache-2.0 — [BackendKit Labs](https://github.com/BackendKit-labs)
|