adaptive-concurrency 0.1.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.
Files changed (157) hide show
  1. package/dist/Limit.d.ts +29 -0
  2. package/dist/Limit.d.ts.map +1 -0
  3. package/dist/Limit.js +1 -0
  4. package/dist/LimitAllotment.d.ts +23 -0
  5. package/dist/LimitAllotment.d.ts.map +1 -0
  6. package/dist/LimitAllotment.js +1 -0
  7. package/dist/Limiter.d.ts +175 -0
  8. package/dist/Limiter.d.ts.map +1 -0
  9. package/dist/Limiter.js +240 -0
  10. package/dist/Listener.d.ts +23 -0
  11. package/dist/Listener.d.ts.map +1 -0
  12. package/dist/Listener.js +1 -0
  13. package/dist/ListenerSet.d.ts +12 -0
  14. package/dist/ListenerSet.d.ts.map +1 -0
  15. package/dist/ListenerSet.js +35 -0
  16. package/dist/MetricIds.d.ts +13 -0
  17. package/dist/MetricIds.d.ts.map +1 -0
  18. package/dist/MetricIds.js +12 -0
  19. package/dist/MetricRegistry.d.ts +66 -0
  20. package/dist/MetricRegistry.d.ts.map +1 -0
  21. package/dist/MetricRegistry.js +30 -0
  22. package/dist/RunResult.d.ts +33 -0
  23. package/dist/RunResult.d.ts.map +1 -0
  24. package/dist/RunResult.js +35 -0
  25. package/dist/StreamingLimit.d.ts +26 -0
  26. package/dist/StreamingLimit.d.ts.map +1 -0
  27. package/dist/StreamingLimit.js +1 -0
  28. package/dist/executors/AdaptiveExecutor.d.ts +50 -0
  29. package/dist/executors/AdaptiveExecutor.d.ts.map +1 -0
  30. package/dist/executors/AdaptiveExecutor.js +80 -0
  31. package/dist/index.d.ts +27 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +28 -0
  34. package/dist/limit/AIMDLimit.d.ts +37 -0
  35. package/dist/limit/AIMDLimit.d.ts.map +1 -0
  36. package/dist/limit/AIMDLimit.js +49 -0
  37. package/dist/limit/FixedLimit.d.ts +15 -0
  38. package/dist/limit/FixedLimit.d.ts.map +1 -0
  39. package/dist/limit/FixedLimit.js +23 -0
  40. package/dist/limit/Gradient2Limit.d.ts +122 -0
  41. package/dist/limit/Gradient2Limit.d.ts.map +1 -0
  42. package/dist/limit/Gradient2Limit.js +107 -0
  43. package/dist/limit/GradientLimit.d.ts +122 -0
  44. package/dist/limit/GradientLimit.d.ts.map +1 -0
  45. package/dist/limit/GradientLimit.js +108 -0
  46. package/dist/limit/SettableLimit.d.ts +18 -0
  47. package/dist/limit/SettableLimit.d.ts.map +1 -0
  48. package/dist/limit/SettableLimit.js +30 -0
  49. package/dist/limit/StreamingLimit.d.ts +26 -0
  50. package/dist/limit/StreamingLimit.d.ts.map +1 -0
  51. package/dist/limit/StreamingLimit.js +1 -0
  52. package/dist/limit/TracingLimitDecorator.d.ts +16 -0
  53. package/dist/limit/TracingLimitDecorator.d.ts.map +1 -0
  54. package/dist/limit/TracingLimitDecorator.js +23 -0
  55. package/dist/limit/VegasLimit.d.ts +85 -0
  56. package/dist/limit/VegasLimit.d.ts.map +1 -0
  57. package/dist/limit/VegasLimit.js +127 -0
  58. package/dist/limit/WindowedLimit.d.ts +48 -0
  59. package/dist/limit/WindowedLimit.d.ts.map +1 -0
  60. package/dist/limit/WindowedLimit.js +67 -0
  61. package/dist/limit/statistics/ExpMovingAverage.d.ts +21 -0
  62. package/dist/limit/statistics/ExpMovingAverage.d.ts.map +1 -0
  63. package/dist/limit/statistics/ExpMovingAverage.js +43 -0
  64. package/dist/limit/statistics/Minimum.d.ts +12 -0
  65. package/dist/limit/statistics/Minimum.d.ts.map +1 -0
  66. package/dist/limit/statistics/Minimum.js +22 -0
  67. package/dist/limit/statistics/MinimumValue.d.ts +12 -0
  68. package/dist/limit/statistics/MinimumValue.d.ts.map +1 -0
  69. package/dist/limit/statistics/MinimumValue.js +22 -0
  70. package/dist/limit/statistics/SingleMeasurement.d.ts +12 -0
  71. package/dist/limit/statistics/SingleMeasurement.d.ts.map +1 -0
  72. package/dist/limit/statistics/SingleMeasurement.js +21 -0
  73. package/dist/limit/statistics/StreamingStatistic.d.ts +29 -0
  74. package/dist/limit/statistics/StreamingStatistic.d.ts.map +1 -0
  75. package/dist/limit/statistics/StreamingStatistic.js +1 -0
  76. package/dist/limit/utils/index.d.ts +10 -0
  77. package/dist/limit/utils/index.d.ts.map +1 -0
  78. package/dist/limit/utils/index.js +19 -0
  79. package/dist/limit/window/AverageSampleWindow.d.ts +4 -0
  80. package/dist/limit/window/AverageSampleWindow.d.ts.map +1 -0
  81. package/dist/limit/window/AverageSampleWindow.js +46 -0
  82. package/dist/limit/window/PercentileSampleWindow.d.ts +38 -0
  83. package/dist/limit/window/PercentileSampleWindow.d.ts.map +1 -0
  84. package/dist/limit/window/PercentileSampleWindow.js +81 -0
  85. package/dist/limit/window/SampleWindow.d.ts +30 -0
  86. package/dist/limit/window/SampleWindow.d.ts.map +1 -0
  87. package/dist/limit/window/SampleWindow.js +1 -0
  88. package/dist/limiter/AbstractLimiter.d.ts +48 -0
  89. package/dist/limiter/AbstractLimiter.d.ts.map +1 -0
  90. package/dist/limiter/AbstractLimiter.js +78 -0
  91. package/dist/limiter/AbstractPartitionedLimiter.d.ts +66 -0
  92. package/dist/limiter/AbstractPartitionedLimiter.d.ts.map +1 -0
  93. package/dist/limiter/AbstractPartitionedLimiter.js +209 -0
  94. package/dist/limiter/BlockingLimiter.d.ts +55 -0
  95. package/dist/limiter/BlockingLimiter.d.ts.map +1 -0
  96. package/dist/limiter/BlockingLimiter.js +111 -0
  97. package/dist/limiter/DelayedRejectStrategy.d.ts +32 -0
  98. package/dist/limiter/DelayedRejectStrategy.d.ts.map +1 -0
  99. package/dist/limiter/DelayedRejectStrategy.js +60 -0
  100. package/dist/limiter/DelayedThenBlockingRejection.d.ts +19 -0
  101. package/dist/limiter/DelayedThenBlockingRejection.d.ts.map +1 -0
  102. package/dist/limiter/DelayedThenBlockingRejection.js +26 -0
  103. package/dist/limiter/FifoBlockingRejection.d.ts +26 -0
  104. package/dist/limiter/FifoBlockingRejection.d.ts.map +1 -0
  105. package/dist/limiter/FifoBlockingRejection.js +77 -0
  106. package/dist/limiter/LifoBlockingLimiter.d.ts +53 -0
  107. package/dist/limiter/LifoBlockingLimiter.d.ts.map +1 -0
  108. package/dist/limiter/LifoBlockingLimiter.js +108 -0
  109. package/dist/limiter/LifoBlockingRejection.d.ts +31 -0
  110. package/dist/limiter/LifoBlockingRejection.d.ts.map +1 -0
  111. package/dist/limiter/LifoBlockingRejection.js +63 -0
  112. package/dist/limiter/PartitionedStrategy.d.ts +90 -0
  113. package/dist/limiter/PartitionedStrategy.d.ts.map +1 -0
  114. package/dist/limiter/PartitionedStrategy.js +183 -0
  115. package/dist/limiter/SimpleLimiter.d.ts +31 -0
  116. package/dist/limiter/SimpleLimiter.d.ts.map +1 -0
  117. package/dist/limiter/SimpleLimiter.js +119 -0
  118. package/dist/limiter/factories/index.d.ts +7 -0
  119. package/dist/limiter/factories/index.d.ts.map +1 -0
  120. package/dist/limiter/factories/index.js +6 -0
  121. package/dist/limiter/factories/makeBlockingLimiter.d.ts +6 -0
  122. package/dist/limiter/factories/makeBlockingLimiter.d.ts.map +1 -0
  123. package/dist/limiter/factories/makeBlockingLimiter.js +8 -0
  124. package/dist/limiter/factories/makeLifoBlockingLimiter.d.ts +8 -0
  125. package/dist/limiter/factories/makeLifoBlockingLimiter.d.ts.map +1 -0
  126. package/dist/limiter/factories/makeLifoBlockingLimiter.js +15 -0
  127. package/dist/limiter/factories/makePartitionedBlockingLimiter.d.ts +12 -0
  128. package/dist/limiter/factories/makePartitionedBlockingLimiter.d.ts.map +1 -0
  129. package/dist/limiter/factories/makePartitionedBlockingLimiter.js +35 -0
  130. package/dist/limiter/factories/makePartitionedLifoBlockingLimiter.d.ts +14 -0
  131. package/dist/limiter/factories/makePartitionedLifoBlockingLimiter.d.ts.map +1 -0
  132. package/dist/limiter/factories/makePartitionedLifoBlockingLimiter.js +38 -0
  133. package/dist/limiter/factories/makePartitionedLimiter.d.ts +11 -0
  134. package/dist/limiter/factories/makePartitionedLimiter.d.ts.map +1 -0
  135. package/dist/limiter/factories/makePartitionedLimiter.js +30 -0
  136. package/dist/limiter/factories/makeSimpleLimiter.d.ts +3 -0
  137. package/dist/limiter/factories/makeSimpleLimiter.d.ts.map +1 -0
  138. package/dist/limiter/factories/makeSimpleLimiter.js +9 -0
  139. package/dist/limiter/factories.d.ts +31 -0
  140. package/dist/limiter/factories.d.ts.map +1 -0
  141. package/dist/limiter/factories.js +74 -0
  142. package/dist/statistics/ExpMovingAverage.d.ts +21 -0
  143. package/dist/statistics/ExpMovingAverage.d.ts.map +1 -0
  144. package/dist/statistics/ExpMovingAverage.js +43 -0
  145. package/dist/statistics/MinimumValue.d.ts +12 -0
  146. package/dist/statistics/MinimumValue.d.ts.map +1 -0
  147. package/dist/statistics/MinimumValue.js +22 -0
  148. package/dist/statistics/MostRecentValue.d.ts +12 -0
  149. package/dist/statistics/MostRecentValue.d.ts.map +1 -0
  150. package/dist/statistics/MostRecentValue.js +21 -0
  151. package/dist/statistics/StreamingStatistic.d.ts +29 -0
  152. package/dist/statistics/StreamingStatistic.d.ts.map +1 -0
  153. package/dist/statistics/StreamingStatistic.js +1 -0
  154. package/dist/utils/index.d.ts +10 -0
  155. package/dist/utils/index.d.ts.map +1 -0
  156. package/dist/utils/index.js +19 -0
  157. package/package.json +31 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Contract for an algorithm that calculates a concurrency limit based on
3
+ * rtt measurements.
4
+ */
5
+ export interface Limit {
6
+ /**
7
+ * @returns Current estimated limit
8
+ */
9
+ getLimit(): number;
10
+ /**
11
+ * Register a callback to receive notification whenever the limit is updated
12
+ * to a new value.
13
+ *
14
+ * Returns a function to unsubscribe. Optional AbortSignal support is
15
+ * provided for ergonomic cancellation.
16
+ */
17
+ notifyOnChange(consumer: (newLimit: number) => void, options?: {
18
+ signal?: AbortSignal;
19
+ }): () => void;
20
+ /**
21
+ * Adjust the estimated limit using a completed request sample.
22
+ * @param startTime Start time in fractional milliseconds (from performance.now())
23
+ * @param rtt Round trip time in fractional milliseconds
24
+ * @param inflight Number of inflight requests at the time the request started
25
+ * @param didDrop Whether the request was dropped (timeout or rejection)
26
+ */
27
+ adjustForSample(startTime: number, rtt: number, inflight: number, didDrop: boolean): void;
28
+ }
29
+ //# sourceMappingURL=Limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Limit.d.ts","sourceRoot":"","sources":["../src/Limit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,QAAQ,IAAI,MAAM,CAAC;IAEnB;;;;;;OAMG;IACH,cAAc,CACZ,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EACpC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,MAAM,IAAI,CAAC;IAEd;;;;;;OAMG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3F"}
package/dist/Limit.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Handle returned when a concurrency slot is acquired. The caller must invoke
3
+ * exactly one of the report methods when the operation completes.
4
+ */
5
+ export interface LimitAllotment {
6
+ /**
7
+ * The operation succeeded and internally measured latency should be used as
8
+ * an RTT sample.
9
+ */
10
+ reportSuccess(): void;
11
+ /**
12
+ * The operation failed before any meaningful RTT measurement could be made
13
+ * and should be ignored so it does not introduce an artificially low RTT.
14
+ */
15
+ reportIgnore(): void;
16
+ /**
17
+ * The request failed and was dropped due to being rejected by an external
18
+ * limit or hitting a timeout. Loss based StreamingLimit implementations will
19
+ * likely do an aggressive reduction in limit when this happens.
20
+ */
21
+ reportDropped(): void;
22
+ }
23
+ //# sourceMappingURL=LimitAllotment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LimitAllotment.d.ts","sourceRoot":"","sources":["../src/LimitAllotment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,aAAa,IAAI,IAAI,CAAC;IAEtB;;;OAGG;IACH,YAAY,IAAI,IAAI,CAAC;IAErB;;;;OAIG;IACH,aAAa,IAAI,IAAI,CAAC;CACvB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,175 @@
1
+ import type { AdaptiveLimit } from "./limit/StreamingLimit.js";
2
+ import type { LimitAllotment } from "./LimitAllotment.js";
3
+ import type { MetricRegistry } from "./MetricRegistry.js";
4
+ import { QuotaNotAvailable, type RunResult } from "./RunResult.js";
5
+ export type SyncAcquireResult = LimitAllotment | undefined;
6
+ export type AsyncAcquireResult = Promise<LimitAllotment | undefined>;
7
+ /**
8
+ * Union of all possible acquire return types. Useful for code that must handle
9
+ * both sync and async limiters generically.
10
+ */
11
+ export type AcquireResult = SyncAcquireResult | AsyncAcquireResult;
12
+ export interface AcquireOptions<ContextT = void> {
13
+ context?: ContextT;
14
+ signal?: AbortSignal;
15
+ }
16
+ /**
17
+ * Read-only view of the limiter's current state, provided to strategies so
18
+ * they can make gating decisions without coupling to the Limiter class.
19
+ */
20
+ export interface LimiterState {
21
+ readonly limit: number;
22
+ readonly inflight: number;
23
+ }
24
+ /**
25
+ * Decides whether a non-bypassed caller may take a concurrency allotment and
26
+ * updates strategy bookkeeping when they may (e.g. permits counter or
27
+ * per-partition tracking).
28
+ */
29
+ export interface AcquireStrategy<ContextT> {
30
+ /**
31
+ * Tries to acquire an allotment for this request under the strategy's rules.
32
+ * When `true`, the strategy has reserved capacity for one inflight unit; when
33
+ * `false`, an allotment was not available.
34
+ */
35
+ tryAcquireAllotment(context: ContextT, state: LimiterState): boolean;
36
+ /**
37
+ * Called when an acquired allotment completes (success, ignore, or drop).
38
+ * Perform any cleanup (e.g. increment permits, release a partition slot).
39
+ */
40
+ onAllotmentReleased(context: ContextT): void;
41
+ /**
42
+ * Called when the adaptive limit changes. The strategy can react
43
+ * (e.g. adjust available permits by the delta, update partition sub-limits).
44
+ */
45
+ onLimitChanged?(oldLimit: number, newLimit: number): void;
46
+ }
47
+ /**
48
+ * Determines what happens when a request is rejected by the
49
+ * {@link AcquireStrategy}. The type parameter `ResultT` flows through to
50
+ * {@link Limiter.acquire}'s return type, enabling the type system to
51
+ * distinguish sync limiters (no promise) from async/blocking ones.
52
+ */
53
+ export interface AllotmentUnavailableStrategy<ContextT, ResultT extends SyncAcquireResult | AsyncAcquireResult> {
54
+ /**
55
+ * Called when the acquire strategy cannot allocate an allotment for a
56
+ * request.
57
+ *
58
+ * @param context The request context.
59
+ * @param retry Callback to re-attempt acquisition. The rejection strategy can
60
+ * call this after a waiter is woken to try again. The retry runs
61
+ * {@link AcquireStrategy.tryAcquireAllotment} and, if successful, returns a
62
+ * ready-to-use allotment with all required wrapping.
63
+ * @param signal Optional abort signal from the caller.
64
+ */
65
+ onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => SyncAcquireResult, signal?: AbortSignal): ResultT;
66
+ /**
67
+ * Called whenever any allotment is released (success, ignore, or drop).
68
+ * Blocking strategies use this to wake queued waiters.
69
+ */
70
+ onAllotmentReleased(): void;
71
+ }
72
+ export interface LimiterOptions<ContextT, RejResultT extends SyncAcquireResult | AsyncAcquireResult = SyncAcquireResult> {
73
+ limit?: AdaptiveLimit;
74
+ /**
75
+ * Clock function returning the current time in fractional milliseconds
76
+ * (like performance.now()). Default: performance.now
77
+ */
78
+ clock?: () => number;
79
+ name?: string;
80
+ metricRegistry?: MetricRegistry;
81
+ /**
82
+ * Predicate that, when returning true for a context, causes the request to
83
+ * bypass the limiter entirely. The request won't affect inflight count or
84
+ * the limit algorithm.
85
+ */
86
+ bypassResolver?: (context: ContextT) => boolean;
87
+ /**
88
+ * Strategy that decides whether a request gets a concurrency slot.
89
+ * Default: SemaphoreStrategy.
90
+ */
91
+ acquireStrategy?: AcquireStrategy<ContextT>;
92
+ /**
93
+ * Strategy that decides what happens when the acquire strategy rejects a
94
+ * request. When omitted, rejected requests immediately receive `undefined`.
95
+ */
96
+ allotmentUnavailableStrategy?: AllotmentUnavailableStrategy<ContextT, RejResultT>;
97
+ }
98
+ /**
99
+ * Concurrency limiter with pluggable strategies for gating decisions and
100
+ * rejection handling.
101
+ *
102
+ * When no rejection strategy is provided, `acquire()` returns synchronously
103
+ * (`LimitAllotment | undefined`). When a blocking rejection strategy is
104
+ * configured, `acquire()` may also return a `Promise`.
105
+ *
106
+ * @typeParam ContextT Request context type (e.g. partition key).
107
+ * @typeParam RejResultT The result type produced by the rejection strategy.
108
+ */
109
+ export declare class Limiter<Context = void, AcquireResult extends SyncAcquireResult | AsyncAcquireResult = SyncAcquireResult> {
110
+ private _inflight;
111
+ private _limit;
112
+ private readonly clock;
113
+ private readonly limitAlgorithm;
114
+ private readonly acquireStrategy;
115
+ private readonly rejectionStrategy;
116
+ private readonly bypassResolver;
117
+ private readonly successCounter;
118
+ private readonly droppedCounter;
119
+ private readonly ignoredCounter;
120
+ private readonly rejectedCounter;
121
+ private readonly bypassCounter;
122
+ static makeDefaultLimit(): AdaptiveLimit;
123
+ constructor(options?: LimiterOptions<Context, AcquireResult>);
124
+ acquire(options?: AcquireOptions<Context>): SyncAcquireResult | AcquireResult;
125
+ private tryAcquireCore;
126
+ private createAllotment;
127
+ getLimit(): number;
128
+ getInflight(): number;
129
+ }
130
+ /**
131
+ * Simple semaphore-based acquire strategy. Tracks a permits counter that is
132
+ * decremented when an allotment is taken and incremented on release. When
133
+ * permits reach zero, {@link tryAcquireAllotment} returns false.
134
+ */
135
+ export declare class SemaphoreStrategy {
136
+ private permits;
137
+ constructor(initialLimit: number);
138
+ tryAcquireAllotment(): boolean;
139
+ onAllotmentReleased(): void;
140
+ onLimitChanged(oldLimit: number, newLimit: number): void;
141
+ }
142
+ /**
143
+ * Run a callback when an acquire result is ready. If the result is a Promise,
144
+ * waits asynchronously; otherwise invokes the callback synchronously.
145
+ */
146
+ export declare function whenAcquireSettled(result: AcquireResult, callback: (allotment: LimitAllotment | undefined) => void): void;
147
+ export type RunCallbackArgs<ContextT> = {
148
+ context: ContextT | undefined;
149
+ signal: AbortSignal | undefined;
150
+ };
151
+ export interface LimitedFunction<ContextT> {
152
+ <T, E extends Error = Error>(fn: (args: RunCallbackArgs<ContextT>) => RunResult<T, E> | Promise<RunResult<T, E>>): Promise<T | typeof QuotaNotAvailable>;
153
+ <T, E extends Error = Error>(options: AcquireOptions<ContextT>, fn: (args: RunCallbackArgs<ContextT>) => RunResult<T, E> | Promise<RunResult<T, E>>): Promise<T | typeof QuotaNotAvailable>;
154
+ }
155
+ /**
156
+ * Creates a helper that runs callbacks under acquired limiter allotments.
157
+ *
158
+ * - If {@link Limiter.acquire} yields no allotment, returns
159
+ * {@link QuotaNotAvailable} without invoking `fn`.
160
+ * - On {@link RunResult} `success` / `ignore`, returns the carried value after
161
+ * reporting to the allotment.
162
+ * - On `dropped`, reports drop and throws the carried error.
163
+ * - On uncaught exceptions from `fn`, reports ignore and rethrows, except for
164
+ * {@link AdaptiveTimeoutError}, which reports drop and rethrows.
165
+ * - Callback receives `{ context, signal }` from acquire options.
166
+ */
167
+ export declare function withLimiter<ContextT, RejResultT extends SyncAcquireResult | AsyncAcquireResult>(limiter: Limiter<ContextT, RejResultT>): LimitedFunction<ContextT>;
168
+ /**
169
+ * Synchronous try-acquire interface. A `Limiter<Ctx>` (with default sync
170
+ * rejection) is structurally compatible with this interface.
171
+ */
172
+ export interface SyncLimiter<ContextT = void> {
173
+ acquire(options?: AcquireOptions<ContextT>): LimitAllotment | undefined;
174
+ }
175
+ //# sourceMappingURL=Limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Limiter.d.ts","sourceRoot":"","sources":["../src/Limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,240 @@
1
+ import { GradientLimit } from "./limit/GradientLimit.js";
2
+ import { MetricIds, NoopMetricRegistry } from "./MetricRegistry.js";
3
+ import { isAdaptiveTimeoutError, QuotaNotAvailable, } from "./RunResult.js";
4
+ // ---------------------------------------------------------------------------
5
+ // Limiter options
6
+ // ---------------------------------------------------------------------------
7
+ const NOOP_ALLOTMENT = {
8
+ reportSuccess() { },
9
+ reportIgnore() { },
10
+ reportDropped() { },
11
+ };
12
+ let idCounter = 0;
13
+ /**
14
+ * Concurrency limiter with pluggable strategies for gating decisions and
15
+ * rejection handling.
16
+ *
17
+ * When no rejection strategy is provided, `acquire()` returns synchronously
18
+ * (`LimitAllotment | undefined`). When a blocking rejection strategy is
19
+ * configured, `acquire()` may also return a `Promise`.
20
+ *
21
+ * @typeParam ContextT Request context type (e.g. partition key).
22
+ * @typeParam RejResultT The result type produced by the rejection strategy.
23
+ */
24
+ export class Limiter {
25
+ _inflight = 0;
26
+ _limit;
27
+ clock;
28
+ limitAlgorithm;
29
+ acquireStrategy;
30
+ rejectionStrategy;
31
+ bypassResolver;
32
+ successCounter;
33
+ droppedCounter;
34
+ ignoredCounter;
35
+ rejectedCounter;
36
+ bypassCounter;
37
+ static makeDefaultLimit() {
38
+ return new GradientLimit();
39
+ }
40
+ constructor(options = {}) {
41
+ this.clock = options.clock ?? (() => performance.now());
42
+ this.limitAlgorithm = options.limit ?? Limiter.makeDefaultLimit();
43
+ this._limit = this.limitAlgorithm.currentLimit;
44
+ this.bypassResolver = options.bypassResolver;
45
+ this.acquireStrategy =
46
+ options.acquireStrategy ?? new SemaphoreStrategy(this._limit);
47
+ this.rejectionStrategy = options.allotmentUnavailableStrategy;
48
+ this.limitAlgorithm.subscribe((newLimit) => {
49
+ const oldLimit = this._limit;
50
+ this._limit = newLimit;
51
+ this.acquireStrategy.onLimitChanged?.(oldLimit, newLimit);
52
+ });
53
+ const registry = options.metricRegistry ?? NoopMetricRegistry;
54
+ const limiterName = options.name ?? `unnamed-${++idCounter}`;
55
+ registry.gauge(MetricIds.LIMIT_NAME, () => this._limit);
56
+ this.successCounter = registry.counter(MetricIds.CALL_NAME, {
57
+ id: limiterName,
58
+ status: "success",
59
+ });
60
+ this.droppedCounter = registry.counter(MetricIds.CALL_NAME, {
61
+ id: limiterName,
62
+ status: "dropped",
63
+ });
64
+ this.ignoredCounter = registry.counter(MetricIds.CALL_NAME, {
65
+ id: limiterName,
66
+ status: "ignored",
67
+ });
68
+ this.rejectedCounter = registry.counter(MetricIds.CALL_NAME, {
69
+ id: limiterName,
70
+ status: "rejected",
71
+ });
72
+ this.bypassCounter = registry.counter(MetricIds.CALL_NAME, {
73
+ id: limiterName,
74
+ status: "bypassed",
75
+ });
76
+ }
77
+ acquire(options) {
78
+ if (options?.signal?.aborted)
79
+ return undefined;
80
+ const ctx = (options?.context ?? undefined);
81
+ if (this.bypassResolver?.(ctx)) {
82
+ this.bypassCounter.increment();
83
+ return NOOP_ALLOTMENT;
84
+ }
85
+ const state = {
86
+ limit: this._limit,
87
+ inflight: this._inflight,
88
+ };
89
+ if (!this.acquireStrategy.tryAcquireAllotment(ctx, state)) {
90
+ this.rejectedCounter.increment();
91
+ if (this.rejectionStrategy) {
92
+ return this.rejectionStrategy.onAllotmentUnavailable(ctx, (retryCtx) => this.tryAcquireCore(retryCtx), options?.signal);
93
+ }
94
+ return undefined;
95
+ }
96
+ return this.createAllotment(ctx);
97
+ }
98
+ tryAcquireCore(ctx) {
99
+ const state = {
100
+ limit: this._limit,
101
+ inflight: this._inflight,
102
+ };
103
+ if (!this.acquireStrategy.tryAcquireAllotment(ctx, state)) {
104
+ return undefined;
105
+ }
106
+ return this.createAllotment(ctx);
107
+ }
108
+ createAllotment(ctx) {
109
+ const startTime = this.clock();
110
+ const currentInflight = ++this._inflight;
111
+ return {
112
+ reportSuccess: () => {
113
+ this._inflight--;
114
+ this.acquireStrategy.onAllotmentReleased(ctx);
115
+ this.successCounter.increment();
116
+ this.limitAlgorithm.addSample(startTime, this.clock() - startTime, currentInflight, false);
117
+ this.rejectionStrategy?.onAllotmentReleased();
118
+ },
119
+ reportIgnore: () => {
120
+ this._inflight--;
121
+ this.acquireStrategy.onAllotmentReleased(ctx);
122
+ this.ignoredCounter.increment();
123
+ this.rejectionStrategy?.onAllotmentReleased();
124
+ },
125
+ reportDropped: () => {
126
+ this._inflight--;
127
+ this.acquireStrategy.onAllotmentReleased(ctx);
128
+ this.droppedCounter.increment();
129
+ this.limitAlgorithm.addSample(startTime, this.clock() - startTime, currentInflight, true);
130
+ this.rejectionStrategy?.onAllotmentReleased();
131
+ },
132
+ };
133
+ }
134
+ getLimit() {
135
+ return this._limit;
136
+ }
137
+ getInflight() {
138
+ return this._inflight;
139
+ }
140
+ }
141
+ // ---------------------------------------------------------------------------
142
+ // Built-in acquire strategy: Semaphore
143
+ // ---------------------------------------------------------------------------
144
+ /**
145
+ * Simple semaphore-based acquire strategy. Tracks a permits counter that is
146
+ * decremented when an allotment is taken and incremented on release. When
147
+ * permits reach zero, {@link tryAcquireAllotment} returns false.
148
+ */
149
+ export class SemaphoreStrategy {
150
+ permits;
151
+ constructor(initialLimit) {
152
+ this.permits = initialLimit;
153
+ }
154
+ tryAcquireAllotment() {
155
+ if (this.permits <= 0)
156
+ return false;
157
+ this.permits--;
158
+ return true;
159
+ }
160
+ onAllotmentReleased() {
161
+ this.permits++;
162
+ }
163
+ onLimitChanged(oldLimit, newLimit) {
164
+ this.permits += newLimit - oldLimit;
165
+ }
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // Helper: whenAcquireSettled
169
+ // ---------------------------------------------------------------------------
170
+ /**
171
+ * Run a callback when an acquire result is ready. If the result is a Promise,
172
+ * waits asynchronously; otherwise invokes the callback synchronously.
173
+ */
174
+ export function whenAcquireSettled(result, callback) {
175
+ if (result !== null &&
176
+ typeof result === "object" &&
177
+ "then" in result &&
178
+ typeof result.then ===
179
+ "function") {
180
+ void result.then(callback);
181
+ }
182
+ else {
183
+ callback(result);
184
+ }
185
+ }
186
+ /**
187
+ * Creates a helper that runs callbacks under acquired limiter allotments.
188
+ *
189
+ * - If {@link Limiter.acquire} yields no allotment, returns
190
+ * {@link QuotaNotAvailable} without invoking `fn`.
191
+ * - On {@link RunResult} `success` / `ignore`, returns the carried value after
192
+ * reporting to the allotment.
193
+ * - On `dropped`, reports drop and throws the carried error.
194
+ * - On uncaught exceptions from `fn`, reports ignore and rethrows, except for
195
+ * {@link AdaptiveTimeoutError}, which reports drop and rethrows.
196
+ * - Callback receives `{ context, signal }` from acquire options.
197
+ */
198
+ export function withLimiter(limiter) {
199
+ async function limited(optionsOrFn, maybeFn) {
200
+ const hasOptions = maybeFn !== undefined;
201
+ const options = hasOptions
202
+ ? optionsOrFn
203
+ : undefined;
204
+ const fn = hasOptions
205
+ ? maybeFn
206
+ : optionsOrFn;
207
+ const allotment = await Promise.resolve(limiter.acquire(options));
208
+ if (!allotment) {
209
+ return QuotaNotAvailable;
210
+ }
211
+ const [result] = await Promise.allSettled([
212
+ fn({
213
+ context: options?.context,
214
+ signal: options?.signal,
215
+ }),
216
+ ]);
217
+ if (result.status === "rejected") {
218
+ if (isAdaptiveTimeoutError(result.reason)) {
219
+ allotment.reportDropped();
220
+ }
221
+ else {
222
+ allotment.reportIgnore();
223
+ }
224
+ throw result.reason;
225
+ }
226
+ const outcome = result.value;
227
+ switch (outcome.kind) {
228
+ case "success":
229
+ allotment.reportSuccess();
230
+ return outcome.value;
231
+ case "ignore":
232
+ allotment.reportIgnore();
233
+ return outcome.value;
234
+ case "dropped":
235
+ allotment.reportDropped();
236
+ throw outcome.error;
237
+ }
238
+ }
239
+ return limited;
240
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Callback interface for the result of a request. The caller must invoke
3
+ * exactly one of these methods when the operation completes.
4
+ */
5
+ export interface Listener {
6
+ /**
7
+ * Notification that the operation succeeded and internally measured latency
8
+ * should be used as an RTT sample.
9
+ */
10
+ onSuccess(): void;
11
+ /**
12
+ * The operation failed before any meaningful RTT measurement could be made
13
+ * and should be ignored to not introduce an artificially low RTT.
14
+ */
15
+ onIgnore(): void;
16
+ /**
17
+ * The request failed and was dropped due to being rejected by an external
18
+ * limit or hitting a timeout. Loss based StreamingLimit implementations will
19
+ * likely do an aggressive reduction in limit when this happens.
20
+ */
21
+ onDropped(): void;
22
+ }
23
+ //# sourceMappingURL=Listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Listener.d.ts","sourceRoot":"","sources":["../src/Listener.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB;;;OAGG;IACH,SAAS,IAAI,IAAI,CAAC;IAElB;;;OAGG;IACH,QAAQ,IAAI,IAAI,CAAC;IAEjB;;;;OAIG;IACH,SAAS,IAAI,IAAI,CAAC;CACnB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Fan-out for numeric change notifications with the same subscribe contract as
3
+ * {@link StreamingLimit.subscribe}.
4
+ */
5
+ export declare class ListenerSet<T extends (this: void, ...args: any[]) => any> {
6
+ private readonly listeners;
7
+ subscribe(consumer: T, options?: {
8
+ signal?: AbortSignal;
9
+ }): () => void;
10
+ notify(...args: Parameters<T>): void;
11
+ }
12
+ //# sourceMappingURL=ListenerSet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListenerSet.d.ts","sourceRoot":"","sources":["../src/ListenerSet.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,WAAW,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;IACpE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAE1C,SAAS,CACP,QAAQ,EAAE,CAAC,EACX,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GACrC,MAAM,IAAI;IA6Bb,MAAM,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;CAKrC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Fan-out for numeric change notifications with the same subscribe contract as
3
+ * {@link StreamingLimit.subscribe}.
4
+ */
5
+ export class ListenerSet {
6
+ listeners = [];
7
+ subscribe(consumer, options = {}) {
8
+ if (options.signal?.aborted) {
9
+ return () => { };
10
+ }
11
+ this.listeners.push(consumer);
12
+ let unsubscribed = false;
13
+ const onAbort = () => {
14
+ unsubscribe();
15
+ };
16
+ const unsubscribe = () => {
17
+ if (unsubscribed) {
18
+ return;
19
+ }
20
+ unsubscribed = true;
21
+ const idx = this.listeners.indexOf(consumer);
22
+ if (idx !== -1) {
23
+ this.listeners.splice(idx, 1);
24
+ }
25
+ options.signal?.removeEventListener("abort", onAbort);
26
+ };
27
+ options.signal?.addEventListener("abort", onAbort, { once: true });
28
+ return unsubscribe;
29
+ }
30
+ notify(...args) {
31
+ for (const listener of this.listeners) {
32
+ listener(...args);
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Common metric ids used by the limiters and limit algorithms.
3
+ */
4
+ export declare const MetricIds: {
5
+ readonly LIMIT_NAME: "limit";
6
+ readonly CALL_NAME: "call";
7
+ readonly INFLIGHT_NAME: "inflight";
8
+ readonly PARTITION_LIMIT_NAME: "limit.partition";
9
+ readonly MIN_RTT_NAME: "min_rtt";
10
+ readonly WINDOW_MIN_RTT_NAME: "min_window_rtt";
11
+ readonly WINDOW_QUEUE_SIZE_NAME: "queue_size";
12
+ };
13
+ //# sourceMappingURL=MetricIds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MetricIds.d.ts","sourceRoot":"","sources":["../src/MetricIds.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;CAQZ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Common metric ids used by the limiters and limit algorithms.
3
+ */
4
+ export const MetricIds = {
5
+ LIMIT_NAME: "limit",
6
+ CALL_NAME: "call",
7
+ INFLIGHT_NAME: "inflight",
8
+ PARTITION_LIMIT_NAME: "limit.partition",
9
+ MIN_RTT_NAME: "min_rtt",
10
+ WINDOW_MIN_RTT_NAME: "min_window_rtt",
11
+ WINDOW_QUEUE_SIZE_NAME: "queue_size",
12
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Common metric ids used by the limiters and limit algorithms.
3
+ */
4
+ export declare const MetricIds: {
5
+ readonly LIMIT_NAME: "limit";
6
+ readonly CALL_NAME: "call";
7
+ readonly INFLIGHT_NAME: "inflight";
8
+ readonly PARTITION_LIMIT_NAME: "limit.partition";
9
+ readonly MIN_RTT_NAME: "min_rtt";
10
+ readonly WINDOW_MIN_RTT_NAME: "min_window_rtt";
11
+ readonly WINDOW_QUEUE_SIZE_NAME: "queue_size";
12
+ };
13
+ /**
14
+ * Listener to receive samples for a distribution.
15
+ */
16
+ export interface DistributionMetric {
17
+ addSample(value: number): void;
18
+ }
19
+ /**
20
+ * A counter that can be incremented when an event occurs. Counters normally
21
+ * translate into an actions-per-second metric.
22
+ */
23
+ export interface Counter {
24
+ increment(): void;
25
+ }
26
+ /** Opaque handle for a registered gauge (supplier is polled by the registry on flush). */
27
+ export interface GaugeMetric {
28
+ }
29
+ /**
30
+ * Simple abstraction for tracking metrics in the limiters.
31
+ */
32
+ export interface MetricRegistry {
33
+ /**
34
+ * Register a sample distribution. Samples are added to the distribution via
35
+ * the returned {@link DistributionMetric}. Will reuse an existing
36
+ * {@link DistributionMetric} if the distribution already exists.
37
+ *
38
+ * @param id Metric identifier
39
+ * @param tagNameValuePairs Pairs of tag name and tag value
40
+ * @returns SampleListener for the caller to add samples
41
+ */
42
+ distribution(id: string, ...tagNameValuePairs: string[]): DistributionMetric;
43
+ /**
44
+ * Register a gauge using the provided supplier. The supplier will be polled
45
+ * whenever the gauge value is flushed by the registry.
46
+ *
47
+ * @param id Metric identifier
48
+ * @param supplier Function that returns the current gauge value
49
+ * @param tagNameValuePairs Pairs of tag name and tag value
50
+ * @returns Registration handle for the gauge
51
+ */
52
+ gauge(id: string, supplier: () => number, ...tagNameValuePairs: string[]): GaugeMetric;
53
+ /**
54
+ * Create a counter that will be incremented when an event occurs.
55
+ *
56
+ * @param id Metric identifier
57
+ * @param attributes Counter attributes/tags
58
+ */
59
+ counter(id: string, attributes: Record<string, string>): Counter;
60
+ }
61
+ /**
62
+ * No-op MetricRegistry that discards all metrics. Used as the default when
63
+ * no registry is configured.
64
+ */
65
+ export declare const NoopMetricRegistry: MetricRegistry;
66
+ //# sourceMappingURL=MetricRegistry.d.ts.map