performance-helpers 1.0.0 → 1.0.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/README.md +12 -2
- package/package.json +146 -1
- package/src/index.js +1 -0
- package/.eslintrc.cjs +0 -22
- package/.nojekyll +0 -0
- package/.prettierrc +0 -6
- package/CONTRIBUTING.md +0 -178
- package/assets/1_Caching.md +0 -4
- package/assets/2_Parallelizing.md +0 -18
- package/assets/3_Logging.md +0 -3
- package/assets/404.md +0 -3
- package/assets/4_Utils.md +0 -10
- package/assets/logo.png +0 -0
- package/assets/navigation.md +0 -10
- package/bench/README.md +0 -97
- package/bench/results.json +0 -94
- package/bench/results.md +0 -233
- package/bench/run.js +0 -2639
- package/bench/worker.js +0 -43
- package/docs/README.md +0 -38
- package/docs/docs-typedoc.json +0 -38714
- package/docs/helpers/constants/README.md +0 -34
- package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_BACKOFF_MAX_MULTIPLIER.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_COOLDOWN_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_INTERVAL_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_MIN_INTERVAL_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_BACKPRESSURE_QUEUE_CAPACITY.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_BACKPRESSURE_REFILL_INTERVAL_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_BATCH_MAX_SIZE.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_CACHE_DEFAULT_TTL_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_CACHE_MAX_POOL_SIZE.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_CACHE_MAX_WEIGHT_BYTES.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_HISTOGRAM_BUCKET_COUNT.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_HISTOGRAM_MAX_VALUE.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_MAX_CLEANUP_PER_TICK.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_QUEUE_CAPACITY.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_REAPER_MIN_INTERVAL_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_REFILL_INTERVAL_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_RETRY_BASE_DELAY_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_RETRY_MAX_DELAY_MS.md +0 -9
- package/docs/helpers/constants/variables/DEFAULT_TIMEOUT_MS.md +0 -9
- package/docs/helpers/constants/variables/ENCODE_CACHE_LARGE_KEY_LENGTH.md +0 -9
- package/docs/helpers/constants/variables/MAX_DEEP_EQUAL_DEPTH.md +0 -9
- package/docs/helpers/constants/variables/MS_PER_MIN.md +0 -9
- package/docs/helpers/constants/variables/MS_PER_SEC.md +0 -9
- package/docs/helpers/constants/variables/default.md +0 -103
- package/docs/helpers/jsdoc-types/README.md +0 -33
- package/docs/helpers/jsdoc-types/interfaces/BufferDecoder.md +0 -23
- package/docs/helpers/jsdoc-types/interfaces/BufferEncoder.md +0 -23
- package/docs/helpers/jsdoc-types/interfaces/CacheNode.md +0 -43
- package/docs/helpers/jsdoc-types/interfaces/CommonPoolOptions.md +0 -31
- package/docs/helpers/jsdoc-types/interfaces/PendingResponseEntry.md +0 -51
- package/docs/helpers/jsdoc-types/interfaces/PostMessageOptions.md +0 -39
- package/docs/helpers/jsdoc-types/interfaces/PowerBatchOptions.md +0 -13
- package/docs/helpers/jsdoc-types/interfaces/PowerCacheOptions.md +0 -115
- package/docs/helpers/jsdoc-types/interfaces/PowerChunkingOptions.md +0 -31
- package/docs/helpers/jsdoc-types/interfaces/PowerCircuitOptions.md +0 -45
- package/docs/helpers/jsdoc-types/interfaces/PowerDeadlineOptions.md +0 -101
- package/docs/helpers/jsdoc-types/interfaces/PowerDeferOptions.md +0 -13
- package/docs/helpers/jsdoc-types/interfaces/PowerEventBusOptions.md +0 -19
- package/docs/helpers/jsdoc-types/interfaces/PowerLatchOptions.md +0 -23
- package/docs/helpers/jsdoc-types/interfaces/PowerLoggerOptions.md +0 -51
- package/docs/helpers/jsdoc-types/interfaces/PowerObserverOptions.md +0 -25
- package/docs/helpers/jsdoc-types/interfaces/PowerPoolOptions.md +0 -85
- package/docs/helpers/jsdoc-types/interfaces/PowerQueueOptions.md +0 -13
- package/docs/helpers/jsdoc-types/interfaces/PowerRetryOptions.md +0 -83
- package/docs/helpers/jsdoc-types/interfaces/PowerSlidingWindowOptions.md +0 -19
- package/docs/helpers/jsdoc-types/interfaces/PowerTTLMapOptions.md +0 -27
- package/docs/helpers/jsdoc-types/interfaces/PowerThrottleOptions.md +0 -31
- package/docs/helpers/jsdoc-types/interfaces/WorkerObj.md +0 -55
- package/docs/helpers/powerBackpressure/README.md +0 -17
- package/docs/helpers/powerBackpressure/classes/PowerBackpressure.md +0 -368
- package/docs/helpers/powerBatch/README.md +0 -17
- package/docs/helpers/powerBatch/classes/PowerBatch.md +0 -139
- package/docs/helpers/powerBuffer/README.md +0 -26
- package/docs/helpers/powerBuffer/functions/b2o.md +0 -25
- package/docs/helpers/powerBuffer/functions/o2b.md +0 -23
- package/docs/helpers/powerBuffer/functions/o2u8.md +0 -33
- package/docs/helpers/powerBuffer/functions/u82o.md +0 -30
- package/docs/helpers/powerBulkhead/README.md +0 -17
- package/docs/helpers/powerBulkhead/classes/PowerBulkhead.md +0 -302
- package/docs/helpers/powerCache/README.md +0 -29
- package/docs/helpers/powerCache/classes/PowerCache.md +0 -933
- package/docs/helpers/powerCache/classes/PowerMemoizer.md +0 -244
- package/docs/helpers/powerCache/classes/PowerTimedCache.md +0 -302
- package/docs/helpers/powerCache/functions/simpleArgsKey.md +0 -31
- package/docs/helpers/powerChunking/README.md +0 -17
- package/docs/helpers/powerChunking/classes/PowerChunker.md +0 -78
- package/docs/helpers/powerCircuit/README.md +0 -23
- package/docs/helpers/powerCircuit/classes/PowerCircuit.md +0 -167
- package/docs/helpers/powerDeadline/README.md +0 -23
- package/docs/helpers/powerDeadline/classes/PowerDeadline.md +0 -88
- package/docs/helpers/powerDefer/README.md +0 -17
- package/docs/helpers/powerDefer/classes/PowerDefer.md +0 -134
- package/docs/helpers/powerEventBus/README.md +0 -23
- package/docs/helpers/powerEventBus/classes/PowerEventBus.md +0 -330
- package/docs/helpers/powerHistogram/README.md +0 -17
- package/docs/helpers/powerHistogram/classes/PowerHistogram.md +0 -285
- package/docs/helpers/powerLatch/README.md +0 -17
- package/docs/helpers/powerLatch/classes/PowerLatch.md +0 -264
- package/docs/helpers/powerLogger/README.md +0 -17
- package/docs/helpers/powerLogger/classes/PowerLogger.md +0 -290
- package/docs/helpers/powerObserver/README.md +0 -23
- package/docs/helpers/powerObserver/classes/PowerObserver.md +0 -213
- package/docs/helpers/powerPermitGate/README.md +0 -11
- package/docs/helpers/powerPermitGate/classes/PowerPermitGate.md +0 -248
- package/docs/helpers/powerPool/README.md +0 -36
- package/docs/helpers/powerPool/classes/PowerPool.md +0 -973
- package/docs/helpers/powerPool/classes/PowerPoolShutdownError.md +0 -67
- package/docs/helpers/powerQueue/README.md +0 -11
- package/docs/helpers/powerQueue/classes/PowerQueue.md +0 -302
- package/docs/helpers/powerRateLimit/README.md +0 -17
- package/docs/helpers/powerRateLimit/classes/PowerRateLimit.md +0 -187
- package/docs/helpers/powerRetry/README.md +0 -23
- package/docs/helpers/powerRetry/classes/PowerRetry.md +0 -106
- package/docs/helpers/powerScheduler/README.md +0 -11
- package/docs/helpers/powerScheduler/classes/PowerScheduler.md +0 -135
- package/docs/helpers/powerSemaphore/README.md +0 -17
- package/docs/helpers/powerSemaphore/classes/PowerSemaphore.md +0 -173
- package/docs/helpers/powerSlidingWindow/README.md +0 -11
- package/docs/helpers/powerSlidingWindow/classes/PowerSlidingWindow.md +0 -83
- package/docs/helpers/powerSubscriberSet/README.md +0 -15
- package/docs/helpers/powerSubscriberSet/classes/PowerSubscriberSet.md +0 -251
- package/docs/helpers/powerSubscriberSet/functions/cleanupWeakRefs.md +0 -21
- package/docs/helpers/powerTTLMap/README.md +0 -17
- package/docs/helpers/powerTTLMap/classes/PowerTTLMap.md +0 -326
- package/docs/helpers/powerThrottle/README.md +0 -17
- package/docs/helpers/powerThrottle/classes/PowerThrottle.md +0 -216
- package/docs/index/README.md +0 -205
- package/docs/utils/errors/README.md +0 -12
- package/docs/utils/errors/functions/formatErrorObj.md +0 -30
- package/docs/utils/errors/functions/normalizeError.md +0 -50
- package/docs/utils/now/README.md +0 -19
- package/docs/utils/now/functions/measureAsync.md +0 -37
- package/docs/utils/now/functions/measureSync.md +0 -54
- package/docs/utils/now/functions/nowMs.md +0 -24
- package/guides/autoscale.md +0 -80
- package/guides/errors.md +0 -41
- package/guides/metaGuide.md +0 -440
- package/guides/now.md +0 -56
- package/guides/powerBackpressure.md +0 -110
- package/guides/powerBatch.md +0 -82
- package/guides/powerBuffer.md +0 -86
- package/guides/powerBulkhead.md +0 -61
- package/guides/powerCache.md +0 -269
- package/guides/powerChunking.md +0 -130
- package/guides/powerCircuit.md +0 -84
- package/guides/powerDeadline.md +0 -99
- package/guides/powerDefer.md +0 -56
- package/guides/powerEventBus.md +0 -89
- package/guides/powerHistogram.md +0 -71
- package/guides/powerLatch.md +0 -94
- package/guides/powerLogger.md +0 -129
- package/guides/powerObserver.md +0 -65
- package/guides/powerPermitGate.md +0 -52
- package/guides/powerPool.md +0 -321
- package/guides/powerQueue.md +0 -112
- package/guides/powerRateLimit.md +0 -37
- package/guides/powerRetry.md +0 -54
- package/guides/powerScheduler.md +0 -41
- package/guides/powerSemaphore.md +0 -65
- package/guides/powerSlidingWindow.md +0 -63
- package/guides/powerSubscriberSet.md +0 -48
- package/guides/powerTTLMap.md +0 -58
- package/guides/powerThrottle.md +0 -152
- package/index.html +0 -57
- package/results.json +0 -6692
- package/scripts/find-missing-jsdoc.js +0 -62
- package/scripts/modernize-optional-chaining.cjs +0 -36
- package/scripts/pool-debug.mjs +0 -29
- package/scripts/repro_powercache.js +0 -14
- package/scripts/static-audit-exports.cjs +0 -93
- package/scripts/static-audit-exports.json +0 -518
- package/test/powerBackpressure.test.js +0 -114
- package/test/powerBatch.branches.extra.test.js +0 -122
- package/test/powerBatch.test.js +0 -79
- package/test/powerBuffer.test.js +0 -125
- package/test/powerBulkhead.test.js +0 -210
- package/test/powerCache.branches.test.js +0 -233
- package/test/powerCache.bulk.test.js +0 -31
- package/test/powerCache.getorset.test.js +0 -110
- package/test/powerCache.hitRate.test.js +0 -35
- package/test/powerCache.inflight.test.js +0 -24
- package/test/powerCache.iterator.test.js +0 -18
- package/test/powerCache.misses.test.js +0 -52
- package/test/powerCache.more.test.js +0 -118
- package/test/powerCache.test.js +0 -37
- package/test/powerCache.timeout.test.js +0 -25
- package/test/powerCache.touch.test.js +0 -46
- package/test/powerChunking.branches.extra.test.js +0 -155
- package/test/powerChunking.errors.test.js +0 -177
- package/test/powerChunking.test.js +0 -39
- package/test/powerCircuit.observability.test.js +0 -71
- package/test/powerCircuit.test.js +0 -74
- package/test/powerDeadline.test.js +0 -140
- package/test/powerDefer.test.js +0 -55
- package/test/powerErrors.test.js +0 -32
- package/test/powerEventBus.branches.extra.test.js +0 -70
- package/test/powerEventBus.extra.test.js +0 -72
- package/test/powerEventBus.max.test.js +0 -43
- package/test/powerEventBus.more.test.js +0 -121
- package/test/powerEventBus.once_off.test.js +0 -17
- package/test/powerEventBus.test.js +0 -74
- package/test/powerEventBus.uncovered.test.js +0 -57
- package/test/powerEventBus.weak.test.js +0 -18
- package/test/powerHistogram.test.js +0 -73
- package/test/powerLatch.branches.extra.test.js +0 -115
- package/test/powerLatch.test.js +0 -57
- package/test/powerLogger.branches.test.js +0 -98
- package/test/powerLogger.formatter.name.test.js +0 -58
- package/test/powerLogger.json.test.js +0 -88
- package/test/powerLogger.output.test.js +0 -81
- package/test/powerLogger.table.debug.test.js +0 -77
- package/test/powerLogger.test.js +0 -59
- package/test/powerMemoizer.memoize.test.js +0 -100
- package/test/powerMemoizer.test.js +0 -85
- package/test/powerObserver.test.js +0 -129
- package/test/powerPermitGate.test.js +0 -66
- package/test/powerPool.autoTransfer.test.js +0 -100
- package/test/powerPool.autoscale.extra.test.js +0 -88
- package/test/powerPool.autoscale.test.js +0 -136
- package/test/powerPool.awaitDefaultTimeout.test.js +0 -52
- package/test/powerPool.awaitTimeout.test.js +0 -22
- package/test/powerPool.batch.test.js +0 -170
- package/test/powerPool.branches.extra2.test.js +0 -42
- package/test/powerPool.branches.test.js +0 -102
- package/test/powerPool.browser.messageerror.test.js +0 -45
- package/test/powerPool.correlation.test.js +0 -26
- package/test/powerPool.correlationId.test.js +0 -63
- package/test/powerPool.dispose.test.js +0 -49
- package/test/powerPool.drain.test.js +0 -57
- package/test/powerPool.events.test.js +0 -131
- package/test/powerPool.more.extra.test.js +0 -99
- package/test/powerPool.more.test.js +0 -283
- package/test/powerPool.node.messageerror.test.js +0 -46
- package/test/powerPool.postMessage.promise.test.js +0 -83
- package/test/powerPool.queueHigh.test.js +0 -55
- package/test/powerPool.queueSaturation.test.js +0 -51
- package/test/powerPool.rapidResize.test.js +0 -55
- package/test/powerPool.resize.overload.test.js +0 -65
- package/test/powerPool.resize.test.js +0 -70
- package/test/powerPool.shutdown.test.js +0 -38
- package/test/powerPool.stats.test.js +0 -40
- package/test/powerPool.stopThePress.test.js +0 -94
- package/test/powerPool.terminateShutdown.test.js +0 -22
- package/test/powerPool.test.js +0 -525
- package/test/powerPool.timers.test.js +0 -55
- package/test/powerPool.uncovered.test.js +0 -407
- package/test/powerPool.workerId.test.js +0 -47
- package/test/powerQueue.iterators.test.js +0 -67
- package/test/powerQueue.saturation.test.js +0 -18
- package/test/powerQueue.test.js +0 -48
- package/test/powerQueue.unshiftMany.test.js +0 -49
- package/test/powerRateLimit.atomic.test.js +0 -80
- package/test/powerRateLimit.extra.test.js +0 -145
- package/test/powerRateLimit.functions.test.js +0 -106
- package/test/powerRateLimit.test.js +0 -38
- package/test/powerRetry.attemptTimeout.test.js +0 -51
- package/test/powerRetry.test.js +0 -121
- package/test/powerScheduler.test.js +0 -126
- package/test/powerSemaphore.test.js +0 -108
- package/test/powerSlidingWindow.pool.test.js +0 -55
- package/test/powerSlidingWindow.test.js +0 -25
- package/test/powerSubscriberSet.test.js +0 -125
- package/test/powerTTLMap.test.js +0 -125
- package/test/powerThrottle.pool.test.js +0 -54
- package/test/powerThrottle.refill.test.js +0 -22
- package/test/powerThrottle.reserve.test.js +0 -46
- package/test/powerThrottle.test.js +0 -45
- package/test/powerTimedCache.test.js +0 -73
- package/test/umd.bundle.branches.test.js +0 -100
- package/test/umd.bundle.cache-timers.test.js +0 -48
- package/test/umd.bundle.exhaustive.test.js +0 -158
- package/test/umd.bundle.fuzz.test.js +0 -86
- package/test/umd.bundle.hasEqual.more.test.js +0 -68
- package/test/umd.bundle.hasEqual.test.js +0 -104
- package/test/umd.bundle.logger-extra.test.js +0 -48
- package/test/umd.bundle.more-coverage-2.test.js +0 -67
- package/test/umd.bundle.pool.test.js +0 -134
- package/test/umd.bundle.test.js +0 -265
- package/test/utils.measure.test.js +0 -49
- package/test/utils.now.extra.test.js +0 -30
- package/test/utils.now.more.test.js +0 -57
- package/tsconfig.json +0 -16
- package/typedoc.json +0 -25
- package/vite.config.js +0 -31
- package/vitest.config.js +0 -17
package/guides/powerBuffer.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# Buffer helpers
|
|
2
|
-
|
|
3
|
-
Lightweight helpers for encoding/decoding JSON to/from binary (Uint8Array / ArrayBuffer / Node Buffer).
|
|
4
|
-
|
|
5
|
-
`powerBuffer` provides tiny, allocation-friendly helpers optimized for passing JSON payloads through transferable binary buffers (for example, when posting messages to Workers). It prefers zero-copy views for ArrayBuffer/TypedArray inputs and falls back to `TextEncoder`/`TextDecoder` (or Node `Buffer`) when available.
|
|
6
|
-
|
|
7
|
-
## o2u8(obj)
|
|
8
|
-
|
|
9
|
-
Encode a value to a `Uint8Array` (UTF-8 JSON).
|
|
10
|
-
|
|
11
|
-
- `obj` — Any value to encode. If the value is already a `Uint8Array`/TypedArray/ArrayBuffer it will be returned or converted to a view.
|
|
12
|
-
|
|
13
|
-
Returns: `Uint8Array` — UTF-8 encoded bytes. Throws if no encoder is available in the environment.
|
|
14
|
-
|
|
15
|
-
Example
|
|
16
|
-
```javascript
|
|
17
|
-
import { o2u8, u82o } from '../src/helpers/powerBuffer.js';
|
|
18
|
-
|
|
19
|
-
// encode a JSON payload to transferable Uint8Array and post to a worker
|
|
20
|
-
const payload = { id: 42, name: 'big-image', meta: { size: 1024 * 1024 } };
|
|
21
|
-
const bytes = o2u8(payload);
|
|
22
|
-
// `bytes.buffer` can be transferred to a Worker to avoid structured-clone copies
|
|
23
|
-
worker.postMessage(bytes, [bytes.buffer]);
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## u82o(buf)
|
|
27
|
-
|
|
28
|
-
Decode a binary buffer (Uint8Array/ArrayBuffer/Buffer) containing JSON UTF-8 to a JS value.
|
|
29
|
-
|
|
30
|
-
- `buf` — The binary input to decode. Accepted types: `Uint8Array`, `ArrayBuffer`, TypedArray, or Node `Buffer`.
|
|
31
|
-
|
|
32
|
-
Returns: parsed JS value. Throws `TypeError` for unsupported input types or malformed UTF-8 JSON.
|
|
33
|
-
|
|
34
|
-
Example — worker receiver
|
|
35
|
-
|
|
36
|
-
```javascript
|
|
37
|
-
import { u82o } from '../src/helpers/powerBuffer.js';
|
|
38
|
-
|
|
39
|
-
self.onmessage = (e) => {
|
|
40
|
-
// decode transferable Uint8Array back to JS value
|
|
41
|
-
const obj = u82o(e.data);
|
|
42
|
-
// process obj
|
|
43
|
-
};
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## o2b(obj)
|
|
47
|
-
|
|
48
|
-
Encode to an `ArrayBuffer` (legacy API). Returns an owning ArrayBuffer (slice if necessary).
|
|
49
|
-
|
|
50
|
-
Parameters: same as `o2u8`.
|
|
51
|
-
|
|
52
|
-
Returns: `ArrayBuffer`.
|
|
53
|
-
|
|
54
|
-
## b2o(buf)
|
|
55
|
-
|
|
56
|
-
Legacy wrapper around `u82o` for ArrayBuffer/TypedArray/Buffer.
|
|
57
|
-
|
|
58
|
-
## Recommendations
|
|
59
|
-
|
|
60
|
-
- Use `o2u8`/`u82o` when sending/receiving structured JSON through `postMessage` to make use of transferables and reduce copy overhead.
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
// worker.js
|
|
64
|
-
self.onmessage(e => {
|
|
65
|
-
const json_input = u82o(e.data);
|
|
66
|
-
...
|
|
67
|
-
const output = o2u8(json_output);
|
|
68
|
-
self.postMessage(output, [output.buffer])
|
|
69
|
-
})
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
// worker.js
|
|
74
|
-
self.onmessage = (e) => {
|
|
75
|
-
const jsonInput = u82o(e.data);
|
|
76
|
-
const result = process(jsonInput);
|
|
77
|
-
const out = o2u8(result);
|
|
78
|
-
self.postMessage(out, [out.buffer]);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// main thread
|
|
82
|
-
worker.onmessage = (e) => {
|
|
83
|
-
const jsonOut = u82o(e.data);
|
|
84
|
-
handleResult(jsonOut);
|
|
85
|
-
};
|
|
86
|
-
```
|
package/guides/powerBulkhead.md
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# PowerBulkhead
|
|
2
|
-
|
|
3
|
-
A partitioned executor that isolates noisy workloads into separate concurrency lanes.
|
|
4
|
-
|
|
5
|
-
Use `PowerBulkhead` when you need to protect critical work from a noisy producer or a hot key. Tasks routed to one partition will queue and run independently from tasks in other partitions.
|
|
6
|
-
|
|
7
|
-
## Constructor
|
|
8
|
-
|
|
9
|
-
| option | type | default | description |
|
|
10
|
-
|---|---:|---:|---|
|
|
11
|
-
| `partitions` | `number` | `4` | Number of isolated execution partitions. Work in different partitions does not compete for the same concurrency slots.
|
|
12
|
-
| `maxConcurrency` | `number` | `1` | Maximum concurrent tasks allowed per partition.
|
|
13
|
-
| `queueCapacity` | `number` | `100` | Maximum number of tasks that may wait in the queue across all partitions.
|
|
14
|
-
| `partitioner` | `Function` | `null` | Optional function `(key) => partitionIndex` used to route a task based on a custom key.
|
|
15
|
-
|
|
16
|
-
## API
|
|
17
|
-
|
|
18
|
-
- `run(task, options)` — Enqueue a task for execution. When the chosen partition has available concurrency, the task runs immediately; otherwise it waits in that partition's queue.
|
|
19
|
-
- `tryRun(task, options)` — Attempt immediate execution and return a `Promise` if the partition has capacity, or `null` if it would have to queue.
|
|
20
|
-
- `drain()` — Wait until all active and queued tasks complete.
|
|
21
|
-
- `partitions` — Number of configured partitions.
|
|
22
|
-
- `maxConcurrency` — Maximum concurrent tasks per partition.
|
|
23
|
-
- `queueCapacity` — Maximum queue size across all partitions.
|
|
24
|
-
- `active` — Number of tasks currently running.
|
|
25
|
-
- `pending` — Number of tasks currently queued.
|
|
26
|
-
- `isFull` — `true` when the helper has reached its global queue capacity.
|
|
27
|
-
|
|
28
|
-
## Example
|
|
29
|
-
|
|
30
|
-
```js
|
|
31
|
-
import { PowerBulkhead } from '../src/helpers/powerBulkhead.js';
|
|
32
|
-
|
|
33
|
-
const bulkhead = new PowerBulkhead({
|
|
34
|
-
partitions: 3,
|
|
35
|
-
maxConcurrency: 2,
|
|
36
|
-
queueCapacity: 20,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
async function submitWork(item, partitionKey) {
|
|
40
|
-
return bulkhead.run(() => {
|
|
41
|
-
// any work can be async
|
|
42
|
-
return fetch(`/api/resource/${item.id}`).then((res) => res.json());
|
|
43
|
-
}, { partitionKey });
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const results = await Promise.all([
|
|
47
|
-
submitWork({ id: 1 }, 'critical'),
|
|
48
|
-
submitWork({ id: 2 }, 'critical'),
|
|
49
|
-
submitWork({ id: 3 }, 'background'),
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
|
-
await bulkhead.drain();
|
|
53
|
-
console.log('all work finished');
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Notes
|
|
57
|
-
|
|
58
|
-
- `PowerBulkhead` uses an internal `PowerQueue` for each partition to keep queued tasks O(1) on enqueue/dequeue.
|
|
59
|
-
- Tasks with the same `partitionKey` are routed to the same partition by default, so noisy or bursty keys can be isolated from healthier lanes.
|
|
60
|
-
- If `queueCapacity` is reached, `run()` rejects immediately with `PowerBulkhead queue is full`.
|
|
61
|
-
- Because partitions do not steal capacity from each other, a hot partition cannot block progress in other partitions.
|
package/guides/powerCache.md
DELETED
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
# LRU cache with TTL and Memoizer
|
|
2
|
-
|
|
3
|
-
An in-memory, memory-efficient LRU cache with TTL, weighted eviction and an optional reusable node pool. Includes a small `PowerMemoizer` wrapper built on top of `PowerCache` for memoizing synchronous or Promise-returning functions.
|
|
4
|
-
|
|
5
|
-
## PowerCache
|
|
6
|
-
|
|
7
|
-
| option | type | default | description |
|
|
8
|
-
|---|---:|---:|---|
|
|
9
|
-
| `maxEntries` | `number` | `Infinity` | Maximum number of entries to retain. Older entries are evicted when exceeded. |
|
|
10
|
-
| `maxWeight` | `number` | `Infinity` | Maximum total weight across all entries. Eviction occurs when exceeded. |
|
|
11
|
-
| `weightFn` | `function(value):number` | `() => 1` | Compute the weight for a value when explicit `weight` not provided to `set`. |
|
|
12
|
-
| `defaultTTL` | `number` | `60000` | Default time-to-live (ms) for entries. Use `null`/`Infinity` to disable expiration. |
|
|
13
|
-
| `maxPoolSize` | `number` | `1000` | Maximum size of the internal node pool used to reuse nodes and reduce GC. |
|
|
14
|
-
| `rejectOversized` | `boolean` | `false` | When `true`, inserting an item with weight > `maxWeight` will be rejected. |
|
|
15
|
-
| `onEvict` | `function(key,value,reason)` | `null` | Callback invoked for evicted/deleted/rejected entries. `reason` is `'evicted'|'deleted'|'rejected-oversized'`. |
|
|
16
|
-
| `onExpire` | `function(key,value)` | `null` | Callback invoked when an entry expires due to TTL. |
|
|
17
|
-
| `initialPoolSize` | `number` | `0` | Prefill the internal node pool to reduce early allocations. |
|
|
18
|
-
| `maxCleanupPerTick` | `number` | `100` | Max nodes scanned per cleanup tick for `startCleanup()`.
|
|
19
|
-
| `eagerCleanupOnRead` | `boolean` | `false` | If `true`, `peek()` and `has()` will remove expired nodes when observed (opt-in behavior). |
|
|
20
|
-
|
|
21
|
-
### API
|
|
22
|
-
|
|
23
|
-
- `set(key, value, { ttl, weight })` — Add or update an entry. Accepts an optional `{ ttl, weight }` options object; returns `this` on success or `false` when insertion is rejected due to `rejectOversized`.
|
|
24
|
-
|
|
25
|
-
- `get(key)` — Retrieve the stored value and mark the entry as recently used. Returns the value or `undefined` when missing or expired.
|
|
26
|
-
|
|
27
|
-
- `peek(key)` — Read the value without affecting recency; returns `value | undefined`. When the cache is constructed with `eagerCleanupOnRead: true`, `peek()` will remove expired entries it encounters.
|
|
28
|
-
|
|
29
|
-
- `has(key, { ignoreExpiry = false })` — Check whether a key exists and is not expired. When `ignoreExpiry` is true expired entries are considered present. When `eagerCleanupOnRead: true` the call will remove expired entries seen during the check.
|
|
30
|
-
|
|
31
|
-
- `hasEqual(key, value, { ignoreExpiry = false, seen })` — Deep-equality compare the stored value against `value` using optimized fast paths for primitives, typed arrays, Maps/Sets, and cyclic-safe comparison. Respects the `ignoreExpiry` option. When performing many comparisons, pass a reusable `WeakMap` as `seen` or use `hasEqualWithSeen(key, value, seen)` to avoid per-call WeakMap allocations.
|
|
32
|
-
|
|
33
|
-
- `delete(key)` — Remove an entry. Returns `true` when a key was removed.
|
|
34
|
-
|
|
35
|
-
- `clear()` — Remove all entries and return nodes to the internal pool (no return value).
|
|
36
|
-
|
|
37
|
-
- `cleanupExpiredUpTo(maxScan = Infinity)` — Scan up to `maxScan` nodes for expired entries and remove them; returns the number of nodes scanned in this pass.
|
|
38
|
-
|
|
39
|
-
- `startCleanup(intervalOrOptions)` — Start a periodic, non-blocking cleanup loop. Accepts either a numeric interval (ms) or `{ interval, maxCleanupPerTick }` options.
|
|
40
|
-
|
|
41
|
-
- `stopCleanup()` — Stop the periodic cleanup loop and clear internal timers.
|
|
42
|
-
|
|
43
|
-
- `getOrSet(key, factory, { ttl, weight, staleWhileRevalidate })` — Atomically read-or-compute a value. If `factory` is a function its result (or resolved Promise) is stored and returned. When `staleWhileRevalidate` is enabled, an expired value can be returned immediately while refresh happens in the background.
|
|
44
|
-
|
|
45
|
-
- `getOrSetAsync(key, asyncFactory, { ttl, weight, staleWhileRevalidate })` — Async read-or-compute with inflight deduplication: concurrent callers share the same in-flight Promise and the resolved value is cached when settled. With `staleWhileRevalidate: true`, an expired cached value is returned immediately and the async factory refreshes the cache behind the scenes.
|
|
46
|
-
|
|
47
|
-
```javascript
|
|
48
|
-
const cache = new PowerCache({ defaultTTL: 1000 });
|
|
49
|
-
cache.set('user:1', { name: 'Alice' }, { ttl: 1000 });
|
|
50
|
-
|
|
51
|
-
// After the entry expires, staleWhileRevalidate returns the old value immediately
|
|
52
|
-
// and refreshes the cache in the background.
|
|
53
|
-
const stale = cache.getOrSet('user:1', () => fetchUser(1), {
|
|
54
|
-
staleWhileRevalidate: true,
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
- `resize({ maxEntries, maxWeight })` — Change cache caps and trigger eviction as needed.
|
|
59
|
-
|
|
60
|
-
- `entries(order = 'MRU')` — Iterator yielding `[key, value]` pairs in MRU or LRU order. Useful for debugging or bulk exports.
|
|
61
|
-
|
|
62
|
-
- `hitRate` (getter) — Convenience fraction `hits / (hits + misses)` (0 when no samples).
|
|
63
|
-
|
|
64
|
-
- `setMany(entries, { ttl, weight })` — Bulk-insert multiple `[key, value]` pairs; performs a single eviction pass after insertion for efficiency.
|
|
65
|
-
|
|
66
|
-
- `getMany(keys, { ignoreExpiry = false })` — Bulk get; returns a `Map` of found keys -> values.
|
|
67
|
-
|
|
68
|
-
- `touch(key, ttl?)` — Refresh recency and optionally TTL for an existing key; returns `true` when the key existed and was not expired.
|
|
69
|
-
|
|
70
|
-
- `stats()` — Return runtime statistics object: `{ size, weight, hits, misses, evictions, rejected, poolSize, expirations }`.
|
|
71
|
-
|
|
72
|
-
- `hitRate` (getter) — Convenience fraction `hits / (hits + misses)` (0 when no samples).
|
|
73
|
-
|
|
74
|
-
#### Iteration
|
|
75
|
-
|
|
76
|
-
`PowerCache` implements the iterator protocol. Iterating the cache with `for...of` yields `[key, value]` pairs in MRU order (most-recently-used first):
|
|
77
|
-
|
|
78
|
-
```javascript
|
|
79
|
-
const c = new PowerCache();
|
|
80
|
-
c.set('a', 1);
|
|
81
|
-
c.set('b', 2);
|
|
82
|
-
for (const [k, v] of c) {
|
|
83
|
-
console.log(k, v); // 'b' then 'a'
|
|
84
|
-
}
|
|
85
|
-
console.log('hit rate', c.hitRate);
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Opt-in: eager cleanup on read
|
|
89
|
-
|
|
90
|
-
If you prefer reads to automatically remove expired entries when they are observed, construct the cache with `eagerCleanupOnRead: true`. This makes `peek()` and `has()` remove expired nodes seen during the check instead of leaving them until the periodic cleanup.
|
|
91
|
-
|
|
92
|
-
```javascript
|
|
93
|
-
import { PowerCache } from '../src/helpers/powerCache.js';
|
|
94
|
-
|
|
95
|
-
const cache = new PowerCache({ defaultTTL: 1, eagerCleanupOnRead: true });
|
|
96
|
-
cache.set('a', 1, { ttl: 1 });
|
|
97
|
-
// wait for expiry
|
|
98
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
99
|
-
console.log(cache.peek('a')); // undefined; the expired entry is removed
|
|
100
|
-
console.log(cache.has('a', { ignoreExpiry: true })); // false (entry was removed)
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Note: The library currently defaults to non-mutating read behavior (expired entries remain until cleanup). Changing the default to `eagerCleanupOnRead: true` would be a breaking change and should be done as part of a major-version bump.
|
|
104
|
-
|
|
105
|
-
If you need LRU order, use `Array.from(c.entries('LRU'))` or the `entries('LRU')` iterator directly.
|
|
106
|
-
|
|
107
|
-
### Example — caching API responses with async factory
|
|
108
|
-
|
|
109
|
-
```javascript
|
|
110
|
-
import { PowerCache } from '../src/helpers/powerCache.js';
|
|
111
|
-
|
|
112
|
-
// Cache user profiles for 30s to avoid repeated HTTP calls
|
|
113
|
-
const cache = new PowerCache({ maxEntries: 5000, defaultTTL: 30_000 });
|
|
114
|
-
|
|
115
|
-
// Network-only fetch helper (separate from cache logic for clarity)
|
|
116
|
-
async function fetchUserProfileFromNetwork(id) {
|
|
117
|
-
const res = await fetch(`https://api.example.com/users/${id}`);
|
|
118
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
119
|
-
return res.json();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// High-level cached accessor using getOrSetAsync (inflight dedupe + caching)
|
|
123
|
-
async function fetchUserProfile(id) {
|
|
124
|
-
const key = `user:${id}`;
|
|
125
|
-
return cache.getOrSetAsync(
|
|
126
|
-
key,
|
|
127
|
-
() => fetchUserProfileFromNetwork(id),
|
|
128
|
-
{ ttl: 30_000 }
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Concurrent callers for the same key share the inflight request (deduped)
|
|
133
|
-
const [p1, p2] = await Promise.all([fetchUserProfile('alice'), fetchUserProfile('alice')]);
|
|
134
|
-
|
|
135
|
-
// Stale-while-revalidate: return expired value immediately and refresh in background
|
|
136
|
-
const profile = await cache.getOrSetAsync('user:alice', () => fetchUserProfileFromNetwork('alice'), {
|
|
137
|
-
staleWhileRevalidate: true,
|
|
138
|
-
ttl: 30_000,
|
|
139
|
-
});
|
|
140
|
-
console.log('profile', profile);
|
|
141
|
-
|
|
142
|
-
// The cache will not store rejected promises; handle network errors explicitly
|
|
143
|
-
try {
|
|
144
|
-
const bob = await fetchUserProfile('bob');
|
|
145
|
-
console.log('bob', bob.name);
|
|
146
|
-
} catch (err) {
|
|
147
|
-
console.error('Failed to load profile', err);
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
## PowerMemoizer
|
|
153
|
-
|
|
154
|
-
Small memoization helper that uses a `PowerCache` instance internally. It deduplicates concurrent Promise-returning calls and does not cache rejected Promises.
|
|
155
|
-
|
|
156
|
-
The constructor always returns a `PowerMemoizer` instance. Use the instance method `memoize(fn)` to create a callable memoized wrapper for a function. The returned memoized function has helper methods attached (`get`, `has`, `delete`, `clear`, `stats`, `cache`).
|
|
157
|
-
|
|
158
|
-
#### Memoizer constructor params
|
|
159
|
-
|
|
160
|
-
| param | type | default | description |
|
|
161
|
-
|---|---:|---:|---|
|
|
162
|
-
| `fn` | `Function?` | — | Optional function to register with the instance. The constructor will not return a bare function; call `pm.memoize(fn)` to obtain a memoized wrapper (the instance will create a convenience wrapper accessible via `pm.run()` when `fn` is supplied). |
|
|
163
|
-
| `options.keyResolver` | `function(...args):string` | `(...args)=>JSON.stringify(args)` | Function mapping call args to a stable cache key. |
|
|
164
|
-
| `options.cacheOptions` | `Object` | `{}` | Options forwarded to the underlying `PowerCache` constructor (e.g. `defaultTTL`, `maxEntries`, `weightFn`). |
|
|
165
|
-
| `options.ttl` | `number?` | `undefined` | Default TTL (ms) used when caching results for the `fn` passed to the constructor. |
|
|
166
|
-
| `options.weight` | `number?` | `undefined` | Default weight used when caching results for the `fn` passed to the constructor. |
|
|
167
|
-
|
|
168
|
-
You can create an empty `PowerMemoizer` instance and memoize multiple functions that share the same underlying cache by calling `memoize(fn)`:
|
|
169
|
-
|
|
170
|
-
```javascript
|
|
171
|
-
// share a single cache across multiple functions
|
|
172
|
-
const pm = new PowerMemoizer()
|
|
173
|
-
const memoA = pm.memoize(fnA)
|
|
174
|
-
const memoB = pm.memoize(fnB, { ttl: 5000 })
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Memoizer API
|
|
178
|
-
|
|
179
|
-
- `get(...args)` — Retrieve the cached value for the resolved key, or `undefined` when missing.
|
|
180
|
-
|
|
181
|
-
- `has(...args)` — Check presence in the memoizer's underlying cache.
|
|
182
|
-
|
|
183
|
-
- `delete(...args)` — Remove a cached entry and any tracked inflight Promise; returns `true` when removed.
|
|
184
|
-
|
|
185
|
-
- `clear()` — Clear the memoizer's cache and any inflight markers.
|
|
186
|
-
|
|
187
|
-
- `memoize(fn)` — Wrap and return a memoized version of `fn` using this instance's cache. The returned function has helper methods attached (`get`, `has`, `delete`, `clear`, `stats`, `cache`).
|
|
188
|
-
|
|
189
|
-
- `run(...args)` — Convenience alias that invokes the memoized wrapper created from the constructor-supplied function. If the `PowerMemoizer` was constructed without a function, `run()` will throw a `TypeError` instructing callers to use `memoize(fn)`.
|
|
190
|
-
|
|
191
|
-
- `memoize(fn)` — Wrap and return a memoized version of `fn` using this instance's cache. The returned function has helper methods attached (`get`, `has`, `delete`, `clear`, `stats`, `cache`).
|
|
192
|
-
|
|
193
|
-
### Example
|
|
194
|
-
|
|
195
|
-
```javascript
|
|
196
|
-
const fetchUserFn = async (id) => fetch(`/users/${id}`).then(r => r.json())
|
|
197
|
-
// when constructing without an immediate function you must pass the
|
|
198
|
-
// options as the *second* argument (first arg is the optional `fn`):
|
|
199
|
-
const pm = new PowerMemoizer(undefined, { cacheOptions: { defaultTTL: 10_000 } })
|
|
200
|
-
const memo = pm.memoize(fetchUserFn)
|
|
201
|
-
// call the memoized function directly
|
|
202
|
-
await memo(1)
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Fast key resolver
|
|
206
|
-
|
|
207
|
-
For hot paths where most calls use simple scalar arguments (ids, numbers, short strings),
|
|
208
|
-
use the built-in `simpleArgsKey` helper as a faster alternative to `JSON.stringify`:
|
|
209
|
-
|
|
210
|
-
```javascript
|
|
211
|
-
import { PowerMemoizer, simpleArgsKey } from '../src/helpers/powerCache.js'
|
|
212
|
-
|
|
213
|
-
const fetchUserFn = async (id) => fetch(`/users/${id}`).then(r => r.json())
|
|
214
|
-
// use the fast resolver for simple scalar args
|
|
215
|
-
// when a function is supplied to the constructor the instance provides a
|
|
216
|
-
// convenience `run()` alias that invokes the memoized wrapper:
|
|
217
|
-
const pm = new PowerMemoizer(fetchUserFn, { keyResolver: simpleArgsKey })
|
|
218
|
-
await pm.run(1)
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
`simpleArgsKey` performs a cheap, deterministic encoding for primitive args
|
|
222
|
-
and falls back to `JSON.stringify` only when it encounters non-scalar values.
|
|
223
|
-
|
|
224
|
-
## PowerTimedCache
|
|
225
|
-
|
|
226
|
-
`PowerTimedCache` is a small convenience wrapper around `PowerCache` for the common
|
|
227
|
-
pure-TTL use case. It constructs a `PowerCache` with the provided `ttl` used as
|
|
228
|
-
the cache `defaultTTL` and automatically starts the periodic cleanup loop so
|
|
229
|
-
callers don't have to wire `startCleanup()` manually.
|
|
230
|
-
|
|
231
|
-
Use it when you only need simple time-based expiration and want a compact
|
|
232
|
-
one-line construction pattern.
|
|
233
|
-
|
|
234
|
-
Constructor signature
|
|
235
|
-
|
|
236
|
-
```javascript
|
|
237
|
-
new PowerTimedCache(ttl, { maxEntries, interval, maxCleanupPerTick, cacheOptions })
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
| option | type | default | description |
|
|
241
|
-
|---|---:|---:|---|
|
|
242
|
-
| `ttl` | `number` | — | Required. Default TTL (ms) for entries stored in the cache. |
|
|
243
|
-
| `maxEntries` | `number` | `undefined` | Optional: forwarded to the underlying `PowerCache` constructor. |
|
|
244
|
-
| `interval` | `number` | `undefined` | Optional cleanup interval (ms). When provided it is forwarded to `startCleanup()`; otherwise `startCleanup()` uses its own computed default. |
|
|
245
|
-
| `maxCleanupPerTick` | `number` | `undefined` | Optional: when provided forwarded to `startCleanup()` to control nodes scanned per tick. |
|
|
246
|
-
| `cacheOptions` | `Object` | `{}` | Additional options forwarded to `PowerCache` (e.g. `weightFn`, `maxWeight`, `rejectOversized`). |
|
|
247
|
-
|
|
248
|
-
### Example
|
|
249
|
-
|
|
250
|
-
```javascript
|
|
251
|
-
import { PowerTimedCache } from '../src/helpers/powerCache.js';
|
|
252
|
-
|
|
253
|
-
// entries expire after 60s; cleanup runs on the default cadence
|
|
254
|
-
const tc = new PowerTimedCache(60_000, { maxEntries: 1000 });
|
|
255
|
-
|
|
256
|
-
tc.set('k', 1);
|
|
257
|
-
console.log(tc.get('k'));
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Notes
|
|
261
|
-
|
|
262
|
-
- `PowerTimedCache` delegates all public `PowerCache` instance methods (for example `get`, `set`, `delete`, `clear`, `entries`, `stats`) to the underlying cache. Use `tc.cache` to access the raw `PowerCache` instance when you need advanced operations.
|
|
263
|
-
- The wrapper exposes synchronous and async disposal hooks (`[Symbol.dispose]` and `[Symbol.asyncDispose]`) which delegate to the underlying cache
|
|
264
|
-
|
|
265
|
-
## Recommendations
|
|
266
|
-
|
|
267
|
-
- Use `PowerCache` for workloads with bounded memory or to avoid repeated expensive computations.
|
|
268
|
-
- Provide a `weightFn` when storing large binary-like values to enable weight-based eviction.
|
|
269
|
-
- Use `PowerMemoizer` for short-lived Promise caching where concurrent deduplication is desirable. Be careful with `keyResolver` for objects — prefer stable string keys or canonical serializers.
|
package/guides/powerChunking.md
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# PowerChunker
|
|
2
|
-
|
|
3
|
-
A small helper that chunks an iterable and processes items via a `PowerPool`.
|
|
4
|
-
|
|
5
|
-
Use `PowerChunker` when you have a large iterable to process and want to
|
|
6
|
-
parallelize the work across a managed worker pool without writing the pool
|
|
7
|
-
boilerplate yourself.
|
|
8
|
-
|
|
9
|
-
## Constructor
|
|
10
|
-
|
|
11
|
-
| option | type | default | description |
|
|
12
|
-
|---|---:|---:|---|
|
|
13
|
-
| `poolOptions` | `Object` | `{}` | Options forwarded to the `PowerPool` constructor (e.g. `size`, `minSize`, `maxSize`, `idleTimeout`). |
|
|
14
|
-
| `postOptions` | `Object` | `{}` | Options forwarded to `PowerPool.postMessageBatch` (for example `awaitResponse`, `workerId`, `timeout`). |
|
|
15
|
-
| `chunkSize` | `number` | `heuristic` | Explicit chunk size. When omitted the helper computes a conservative chunk size derived from `iterable.length` and pool size (aiming for roughly `poolSize * 4` in-flight chunks). |
|
|
16
|
-
| `fnComplexity` | `'light'\|'medium'\|'heavy'` | `auto` | Hint about per-item work complexity that biases the computed `chunkSize`. When omitted the helper will attempt to analyze `fn`'s source to infer complexity (`'light'\|'medium'\|'heavy'`) and use that to bias chunking; falls back to `'medium'` on failure. |
|
|
17
|
-
|
|
18
|
-
## API
|
|
19
|
-
|
|
20
|
-
- Returns a `PowerPool` instance managing chunked work. The helper forwards `message` events from per-chunk processing to `pool.onmessage`.
|
|
21
|
-
|
|
22
|
-
- `onmessage` / `addEventListener('message', cb)` — Receive per-chunk result events. Each event `data` contains `{ processed, results, correlationId? }`.
|
|
23
|
-
|
|
24
|
-
- `postMessageBatch(items, options)` — The helper uses the underlying pool's `postMessageBatch` for array-mode enqueues; when using streaming mode the helper internally calls `postMessage({ chunk })` for each chunk. The return value mirrors `PowerPool.postMessageBatch` (array of booleans or Promises when awaiting responses).
|
|
25
|
-
|
|
26
|
-
- `drain()` — Await until all queued and inflight chunk tasks have completed. (Inherited from returned `PowerPool` instance.)
|
|
27
|
-
|
|
28
|
-
- `terminate()` / `shutdown()` — Terminate or shutdown the underlying pool; see `PowerPool` semantics for differences.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## Example
|
|
32
|
-
|
|
33
|
-
```javascript
|
|
34
|
-
import { PowerChunker } from '../src/helpers/powerChunking.js';
|
|
35
|
-
import { PowerLogger } from '../src/helpers/powerLogger.js';
|
|
36
|
-
|
|
37
|
-
const data = Array.from({ length: 1000 }, (_, i) => ({ id: i, payload: `item-${i}` }));
|
|
38
|
-
function process(item) {
|
|
39
|
-
// simulate per-item CPU/IO work; in production this would be heavy transform
|
|
40
|
-
return { id: item.id, processed: true };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Create a chunker which internally creates a `PowerPool` sized for concurrency
|
|
44
|
-
const pool = new PowerChunker(data, process, { poolOptions: { size: 4 } });
|
|
45
|
-
|
|
46
|
-
const logger = new PowerLogger(1);
|
|
47
|
-
const results = [];
|
|
48
|
-
const errors = [];
|
|
49
|
-
|
|
50
|
-
pool.onmessage = (e) => {
|
|
51
|
-
const chunk = e && e.data;
|
|
52
|
-
if (!chunk) return;
|
|
53
|
-
const items = Array.isArray(chunk.results) ? chunk.results : [];
|
|
54
|
-
for (const r of items) {
|
|
55
|
-
if (r && r.error) {
|
|
56
|
-
errors.push(r);
|
|
57
|
-
logger.error('chunk item error', r);
|
|
58
|
-
} else {
|
|
59
|
-
results.push(r);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// Wait until the pool is idle (all queued and inflight tasks finished)
|
|
65
|
-
await pool.drain();
|
|
66
|
-
// Pretty-print errors using the per-module logger (uncomment the import above in real code)
|
|
67
|
-
// (example: log chunk processing errors if needed)
|
|
68
|
-
console.log('Results:', results.length, 'Errors:', errors.length);
|
|
69
|
-
pool.terminate();
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Real-world Example — bulk CSV processing
|
|
73
|
-
|
|
74
|
-
```javascript
|
|
75
|
-
import { PowerChunker } from '../src/helpers/powerChunking.js';
|
|
76
|
-
|
|
77
|
-
// `readCsvRows` is a user helper that yields/returns many parsed rows.
|
|
78
|
-
const rows = await readCsvRows('large-export.csv');
|
|
79
|
-
|
|
80
|
-
// transform each row into the shape your backend expects
|
|
81
|
-
async function transformRow(row) {
|
|
82
|
-
// validate/normalize fields, enrich, etc.
|
|
83
|
-
return { id: row.id, ts: Date.parse(row.time), payload: row.data };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Create a chunker tuned for bulk DB writes. Use chunkSize to control
|
|
87
|
-
// batch sizes sent to the worker-like handlers; chunker will post each
|
|
88
|
-
// chunk as a single task to an internal pool which processes items and
|
|
89
|
-
// emits a per-chunk `message` with `results`.
|
|
90
|
-
const pool = new PowerChunker(rows, transformRow, {
|
|
91
|
-
poolOptions: { size: 4 },
|
|
92
|
-
chunkSize: 500,
|
|
93
|
-
postOptions: { awaitResponse: false }
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const errors = [];
|
|
97
|
-
pool.onmessage = (e) => {
|
|
98
|
-
const data = e && e.data;
|
|
99
|
-
if (!data || !Array.isArray(data.results)) return;
|
|
100
|
-
for (const r of data.results) {
|
|
101
|
-
if (r && r.error) errors.push(r);
|
|
102
|
-
else {
|
|
103
|
-
// collect or stream to a DB bulk-inserter here
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
// Wait until all work finishes, then perform any final bulk write or cleanup
|
|
109
|
-
await pool.drain();
|
|
110
|
-
if (errors.length) console.error('Some rows failed', errors.length);
|
|
111
|
-
pool.terminate();
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Notes
|
|
115
|
-
|
|
116
|
-
- This helper creates inline worker-like instances that execute `fn` in a
|
|
117
|
-
microtask (via `setTimeout`) so it works in environments without real Web
|
|
118
|
-
Workers. For real multi-threaded CPU-bound work use a real worker source and
|
|
119
|
-
a `PowerPool` directly.
|
|
120
|
-
- The helper returns what `PowerPool.postMessageBatch` returns: an array of
|
|
121
|
-
per-chunk results (`true|false`) or Promises when `awaitResponse` is used.
|
|
122
|
-
- When `fnComplexity` is not provided the helper will examine the source of `fn` and attempt
|
|
123
|
-
- When `fnComplexity` is not provided the helper uses a lightweight heuristic to infer complexity:
|
|
124
|
-
it treats `AsyncFunction` or `GeneratorFunction` as `heavy` and uses the function's declared
|
|
125
|
-
arity (number of formal parameters) as a signal; otherwise it defaults to `medium`.
|
|
126
|
-
This approach avoids fragile source-parsing while providing a sensible bias for chunk sizing.
|
|
127
|
-
- Each `message` event `data` includes:
|
|
128
|
-
- `processed`: number of items processed in the chunk
|
|
129
|
-
- `results`: array of per-item return values (or error objects `{ error: true, code, message, stack }`)
|
|
130
|
-
- `correlationId` when worker-level correlation was provided
|
package/guides/powerCircuit.md
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
# PowerCircuit
|
|
2
|
-
|
|
3
|
-
Simple circuit breaker primitive to protect external services from cascading failures.
|
|
4
|
-
|
|
5
|
-
## Constructor
|
|
6
|
-
|
|
7
|
-
`new PowerCircuit(options?)`
|
|
8
|
-
|
|
9
|
-
## Options
|
|
10
|
-
|
|
11
|
-
| Option | Type | Default | Description |
|
|
12
|
-
|---|---:|---:|---|
|
|
13
|
-
| `threshold` | `number` | `5` | Consecutive failure threshold to open the circuit. |
|
|
14
|
-
| `timeout` | `number` (ms) | `30000` | Milliseconds to keep the circuit open before allowing a trial (`half-open`) call. |
|
|
15
|
-
|
|
16
|
-
## API
|
|
17
|
-
|
|
18
|
-
- `call(fn)` — Execute the provided function `fn` under circuit protection. Returns a `Promise` resolved with `fn`'s result or rejected if `fn` throws. When the circuit is open `call` will reject immediately with a circuit-open error.
|
|
19
|
-
|
|
20
|
-
- `state` (getter) — One of `'closed' | 'open' | 'half-open'`, indicating the current circuit state.
|
|
21
|
-
|
|
22
|
-
- `failures` (getter) — Number of consecutive failures that have been observed; this counter resets when a call succeeds.
|
|
23
|
-
|
|
24
|
-
- `lastError` — The last error observed from a failed protected call (useful for diagnostics and logging).
|
|
25
|
-
|
|
26
|
-
- `reset()` — Force the circuit into the `closed` state and clear internal counters/history.
|
|
27
|
-
|
|
28
|
-
- `onStateChange` (constructor option) — Optional callback `(state, reason?)` invoked whenever the circuit transitions between states. The callback is called with the new state (`'closed'|'open'|'half-open'`) and an optional reason string such as `'thresholdExceeded'`, `'trialFailed'`, `'timeoutElapsed'`, `'success'`, or `'reset'`. User callback errors are swallowed by the circuit to avoid interfering with control flow.
|
|
29
|
-
|
|
30
|
-
- `eventBus` (constructor option) — Optional instance of `PowerEventBus` to receive `stateChange` events. When provided the circuit will emit `{ state, reason }` objects on the bus under the `'stateChange'` event name.
|
|
31
|
-
|
|
32
|
-
## Example
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
import { PowerCircuit } from '../src/helpers/powerCircuit.js';
|
|
36
|
-
|
|
37
|
-
// Real-world example: protect an HTTP fetch to a flaky external API.
|
|
38
|
-
// Provide observability hooks: callback and an optional event bus.
|
|
39
|
-
import { PowerEventBus } from '../src/helpers/powerEventBus.js';
|
|
40
|
-
const bus = new PowerEventBus();
|
|
41
|
-
|
|
42
|
-
const cb = new PowerCircuit({
|
|
43
|
-
threshold: 3,
|
|
44
|
-
timeout: 5_000,
|
|
45
|
-
onStateChange: (state, reason) => console.log('circuit state ->', state, reason),
|
|
46
|
-
eventBus: bus,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
async function fetchWithCircuit(url, opts) {
|
|
50
|
-
return cb.call(async () => {
|
|
51
|
-
const res = await fetch(url, opts);
|
|
52
|
-
if (!res.ok) throw Object.assign(new Error('HTTP'), { status: res.status });
|
|
53
|
-
return res.json();
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Usage: this attempts the request; after 3 consecutive failures the circuit
|
|
58
|
-
// opens and subsequent calls will immediately reject with `{ code: 'ECIRCUITOPEN' }`.
|
|
59
|
-
async function doWork() {
|
|
60
|
-
try {
|
|
61
|
-
const data = await fetchWithCircuit('https://api.example.com/data');
|
|
62
|
-
console.log('got', data);
|
|
63
|
-
} catch (err) {
|
|
64
|
-
if (err && err.code === 'ECIRCUITOPEN') {
|
|
65
|
-
// fallback behavior while the circuit is open (serve cached data)
|
|
66
|
-
console.warn('service unavailable — serving stale cache');
|
|
67
|
-
return cache.get('latest') || { source: 'stale' };
|
|
68
|
-
}
|
|
69
|
-
console.error('request failed', err);
|
|
70
|
-
throw err;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Observability example
|
|
76
|
-
|
|
77
|
-
You can subscribe to the `PowerEventBus` to centralize state-change handling across multiple circuits or components:
|
|
78
|
-
|
|
79
|
-
```javascript
|
|
80
|
-
bus.on('stateChange', ({ state, reason }) => {
|
|
81
|
-
// record metrics, raise alerts, or update UI
|
|
82
|
-
console.info('circuit-change', state, reason);
|
|
83
|
-
});
|
|
84
|
-
```
|