adaptive-concurrency 0.3.2 → 0.3.4
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/dist/LimitAllotment.d.ts +7 -1
- package/dist/LimitAllotment.d.ts.map +1 -1
- package/dist/Limiter.d.ts +15 -21
- package/dist/Limiter.d.ts.map +1 -1
- package/dist/Limiter.js +99 -56
- package/dist/RunResult.d.ts +12 -6
- package/dist/RunResult.d.ts.map +1 -1
- package/dist/RunResult.js +10 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/limiter/acquire-strategies/PartitionedStrategy.d.ts +34 -5
- package/dist/limiter/acquire-strategies/PartitionedStrategy.d.ts.map +1 -1
- package/dist/limiter/acquire-strategies/PartitionedStrategy.js +34 -9
- package/dist/limiter/acquire-strategies/SemaphoreStrategy.d.ts +13 -0
- package/dist/limiter/acquire-strategies/SemaphoreStrategy.d.ts.map +1 -0
- package/dist/limiter/acquire-strategies/SemaphoreStrategy.js +23 -0
- package/dist/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.d.ts +36 -0
- package/dist/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.d.ts.map +1 -0
- package/dist/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.js +117 -0
- package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.d.ts +2 -1
- package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.d.ts.map +1 -1
- package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.js +10 -2
- package/dist/limiter/allocation-unavailable-strategies/FifoBlockingRejection.d.ts +19 -15
- package/dist/limiter/allocation-unavailable-strategies/FifoBlockingRejection.d.ts.map +1 -1
- package/dist/limiter/allocation-unavailable-strategies/FifoBlockingRejection.js +13 -61
- package/dist/limiter/allocation-unavailable-strategies/LifoBlockingRejection.d.ts +4 -8
- package/dist/limiter/allocation-unavailable-strategies/LifoBlockingRejection.d.ts.map +1 -1
- package/dist/limiter/allocation-unavailable-strategies/LifoBlockingRejection.js +13 -49
- package/dist/limiter/factories/makeBlockingLimiter.d.ts +3 -1
- package/dist/limiter/factories/makeBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makeBlockingLimiter.js +3 -2
- package/dist/limiter/factories/makeLifoBlockingLimiter.d.ts +1 -1
- package/dist/limiter/factories/makeLifoBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makeLifoBlockingLimiter.js +1 -1
- package/dist/limiter/factories/makePartitionedBlockingLimiter.d.ts +3 -1
- package/dist/limiter/factories/makePartitionedBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makePartitionedBlockingLimiter.js +5 -4
- package/dist/limiter/factories/makeSimpleLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makeSimpleLimiter.js +2 -1
- package/dist/utils/LinkedWaiterQueue.d.ts +21 -0
- package/dist/utils/LinkedWaiterQueue.d.ts.map +1 -0
- package/dist/utils/LinkedWaiterQueue.js +81 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/package.json +4 -3
|
@@ -9,9 +9,12 @@ const PARTITION_TAG_NAME = "partition";
|
|
|
9
9
|
* max(1, ceil(globalLimit * percent))`.
|
|
10
10
|
*
|
|
11
11
|
* Admission policy:
|
|
12
|
-
* - If `globalInflight < globalLimit`,
|
|
13
|
-
*
|
|
14
|
-
* exists
|
|
12
|
+
* - If `globalInflight < globalLimit`, admission is controlled by partition
|
|
13
|
+
* burst policy:
|
|
14
|
+
* - `unbounded` (default): always admit while global slack exists.
|
|
15
|
+
* - `capped`: admit up to
|
|
16
|
+
* `ceil(limitAtGlobalSaturation * maxBurstMultiplier)`.
|
|
17
|
+
* - `none`: admit only up to `limitAtGlobalSaturation`.
|
|
15
18
|
*
|
|
16
19
|
* - If `globalInflight >= globalLimit`, admission is checked against the
|
|
17
20
|
* resolved partition's limitAtGlobalSaturation only (`tryAcquire` on that
|
|
@@ -23,8 +26,7 @@ const PARTITION_TAG_NAME = "partition";
|
|
|
23
26
|
*
|
|
24
27
|
* Examples (global limit = 10, A=50%, B=50% => limitsAtGlobalSaturation: A=5,
|
|
25
28
|
* B=5):
|
|
26
|
-
* - **
|
|
27
|
-
* admissions do not enforce per-partition limits at global saturation).
|
|
29
|
+
* - **Unbounded bursting:** A can reach inflight 10 while B is 0.
|
|
28
30
|
*
|
|
29
31
|
* - **Limit-at-global-saturation catch-up at saturation:** if A=10 and B=0,
|
|
30
32
|
* then B requests can still be admitted up to B=5 via `tryAcquire`, so global
|
|
@@ -65,6 +67,7 @@ export class PartitionedStrategy {
|
|
|
65
67
|
new Partition({
|
|
66
68
|
name,
|
|
67
69
|
percent: cfg.percent,
|
|
70
|
+
burstMode: cfg.burstMode ?? { kind: "unbounded" },
|
|
68
71
|
initialLimitAtGlobalSaturation: partitionLimitAtGlobalSaturationForGlobal(initialLimit, cfg.percent),
|
|
69
72
|
registry,
|
|
70
73
|
}),
|
|
@@ -72,9 +75,9 @@ export class PartitionedStrategy {
|
|
|
72
75
|
this.unknownPartition = new Partition({
|
|
73
76
|
name: "unknown",
|
|
74
77
|
percent: 0,
|
|
78
|
+
burstMode: { kind: "unbounded" },
|
|
75
79
|
// Java never calls updateLimit on unknown; limitAtGlobalSaturation stays
|
|
76
|
-
// 0 so
|
|
77
|
-
// tryAcquire always fails at global cap.
|
|
80
|
+
// 0, so tryAcquire always fails at global saturation.
|
|
78
81
|
initialLimitAtGlobalSaturation: 0,
|
|
79
82
|
registry,
|
|
80
83
|
});
|
|
@@ -84,8 +87,7 @@ export class PartitionedStrategy {
|
|
|
84
87
|
if (state.inflight >= state.limit) {
|
|
85
88
|
return partition.tryAcquire();
|
|
86
89
|
}
|
|
87
|
-
partition.
|
|
88
|
-
return true;
|
|
90
|
+
return partition.acquireWithinBurst();
|
|
89
91
|
}
|
|
90
92
|
onAllotmentReleased(context) {
|
|
91
93
|
this.resolvePartition(context).release();
|
|
@@ -107,6 +109,7 @@ export class PartitionedStrategy {
|
|
|
107
109
|
return {
|
|
108
110
|
name: partition.name,
|
|
109
111
|
percent: partition.percent,
|
|
112
|
+
burstMode: partition.burstMode,
|
|
110
113
|
limitAtGlobalSaturation: partition.limitAtGlobalSaturation,
|
|
111
114
|
inFlight: partition.inFlight,
|
|
112
115
|
isLimitAtGlobalSaturationExceeded: partition.isLimitAtGlobalSaturationExceeded,
|
|
@@ -129,6 +132,7 @@ function partitionLimitAtGlobalSaturationForGlobal(totalGlobalLimit, percent) {
|
|
|
129
132
|
class Partition {
|
|
130
133
|
name;
|
|
131
134
|
percent;
|
|
135
|
+
burstMode;
|
|
132
136
|
inflightDistribution;
|
|
133
137
|
limitAtGlobalSaturationGauge;
|
|
134
138
|
_inflight = 0;
|
|
@@ -139,7 +143,12 @@ class Partition {
|
|
|
139
143
|
}
|
|
140
144
|
this.name = init.name;
|
|
141
145
|
this.percent = init.percent;
|
|
146
|
+
this.burstMode = init.burstMode;
|
|
142
147
|
this._limitAtGlobalSaturation = init.initialLimitAtGlobalSaturation;
|
|
148
|
+
if (this.burstMode.kind === "capped" &&
|
|
149
|
+
this.burstMode.maxBurstMultiplier < 1.0) {
|
|
150
|
+
throw new Error("maxBurstMultiplier must be >= 1.0");
|
|
151
|
+
}
|
|
143
152
|
const registry = init.registry;
|
|
144
153
|
this.inflightDistribution = registry.distribution(MetricIds.INFLIGHT_NAME, PARTITION_TAG_NAME, this.name);
|
|
145
154
|
this.limitAtGlobalSaturationGauge = registry.gauge(MetricIds.PARTITION_LIMIT_NAME, () => this._limitAtGlobalSaturation, PARTITION_TAG_NAME, this.name);
|
|
@@ -163,6 +172,13 @@ class Partition {
|
|
|
163
172
|
this._inflight++;
|
|
164
173
|
this.inflightDistribution.addSample(this._inflight);
|
|
165
174
|
}
|
|
175
|
+
acquireWithinBurst() {
|
|
176
|
+
if (this._inflight >= this.burstCapBelowGlobalSaturation()) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
this.acquire();
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
166
182
|
tryAcquire() {
|
|
167
183
|
if (this._inflight < this._limitAtGlobalSaturation) {
|
|
168
184
|
this._inflight++;
|
|
@@ -177,6 +193,15 @@ class Partition {
|
|
|
177
193
|
get inFlight() {
|
|
178
194
|
return this._inflight;
|
|
179
195
|
}
|
|
196
|
+
burstCapBelowGlobalSaturation() {
|
|
197
|
+
if (this.burstMode.kind === "unbounded") {
|
|
198
|
+
return Number.POSITIVE_INFINITY;
|
|
199
|
+
}
|
|
200
|
+
if (this.burstMode.kind === "none") {
|
|
201
|
+
return this._limitAtGlobalSaturation;
|
|
202
|
+
}
|
|
203
|
+
return Math.max(this._limitAtGlobalSaturation, Math.ceil(this._limitAtGlobalSaturation * this.burstMode.maxBurstMultiplier));
|
|
204
|
+
}
|
|
180
205
|
toString() {
|
|
181
206
|
return `Partition [pct=${this.percent}, limitAtGlobalSaturation=${this._limitAtGlobalSaturation}, inflight=${this._inflight}]`;
|
|
182
207
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple semaphore-based acquire strategy. Tracks a permits counter that is
|
|
3
|
+
* decremented when an allotment is taken and incremented on release. When
|
|
4
|
+
* permits reach zero, `tryAcquireAllotment` returns false.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SemaphoreStrategy {
|
|
7
|
+
private permits;
|
|
8
|
+
constructor(initialLimit: number);
|
|
9
|
+
tryAcquireAllotment(): boolean;
|
|
10
|
+
onAllotmentReleased(): void;
|
|
11
|
+
onLimitChanged(oldLimit: number, newLimit: number): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=SemaphoreStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SemaphoreStrategy.d.ts","sourceRoot":"","sources":["../../../src/limiter/acquire-strategies/SemaphoreStrategy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAS;gBAEZ,YAAY,EAAE,MAAM;IAIhC,mBAAmB,IAAI,OAAO;IAM9B,mBAAmB,IAAI,IAAI;IAI3B,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAGzD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple semaphore-based acquire strategy. Tracks a permits counter that is
|
|
3
|
+
* decremented when an allotment is taken and incremented on release. When
|
|
4
|
+
* permits reach zero, `tryAcquireAllotment` returns false.
|
|
5
|
+
*/
|
|
6
|
+
export class SemaphoreStrategy {
|
|
7
|
+
permits;
|
|
8
|
+
constructor(initialLimit) {
|
|
9
|
+
this.permits = initialLimit;
|
|
10
|
+
}
|
|
11
|
+
tryAcquireAllotment() {
|
|
12
|
+
if (this.permits <= 0)
|
|
13
|
+
return false;
|
|
14
|
+
this.permits--;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
onAllotmentReleased() {
|
|
18
|
+
this.permits++;
|
|
19
|
+
}
|
|
20
|
+
onLimitChanged(oldLimit, newLimit) {
|
|
21
|
+
this.permits += newLimit - oldLimit;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LimitAllotment } from "../../LimitAllotment.js";
|
|
2
|
+
import type { AcquireResult, AllotmentUnavailableStrategy } from "../../Limiter.js";
|
|
3
|
+
import type { WaiterHandle } from "../../utils/LinkedWaiterQueue.js";
|
|
4
|
+
type Waiter<ContextT> = {
|
|
5
|
+
context: ContextT;
|
|
6
|
+
retry: (context: ContextT) => AcquireResult;
|
|
7
|
+
handle: WaiterHandle;
|
|
8
|
+
resolve: (allotment: LimitAllotment | undefined) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const MAX_TIMEOUT: number;
|
|
11
|
+
export type BlockingBacklogRejectionOptions<ContextT> = {
|
|
12
|
+
backlogSize: number;
|
|
13
|
+
backlogTimeout: number | ((context: ContextT) => number);
|
|
14
|
+
queue: WaiterQueue<Waiter<ContextT>>;
|
|
15
|
+
};
|
|
16
|
+
export type WaiterQueue<WaiterT extends Waiter<any>> = {
|
|
17
|
+
enqueue: (waiter: Omit<WaiterT, "handle">) => WaiterT;
|
|
18
|
+
peekHead: () => WaiterT | undefined;
|
|
19
|
+
removeByHandle: (handle: WaiterHandle) => boolean;
|
|
20
|
+
size: () => number;
|
|
21
|
+
};
|
|
22
|
+
export declare class BlockingBacklogRejection<ContextT> implements AllotmentUnavailableStrategy<ContextT> {
|
|
23
|
+
private readonly backlogSize;
|
|
24
|
+
private readonly getBacklogTimeout;
|
|
25
|
+
private readonly queue;
|
|
26
|
+
private drainInProgress;
|
|
27
|
+
private releaseDuringDrain;
|
|
28
|
+
constructor(options: BlockingBacklogRejectionOptions<ContextT>);
|
|
29
|
+
onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<LimitAllotment | undefined>;
|
|
30
|
+
onAllotmentReleased(): Promise<void>;
|
|
31
|
+
onLimitChanged(oldLimit: number, newLimit: number): void;
|
|
32
|
+
private waitInBacklog;
|
|
33
|
+
private assertTimeoutWithinBounds;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=BlockingBacklogRejection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockingBacklogRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EACV,aAAa,EACb,4BAA4B,EAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAErE,KAAK,MAAM,CAAC,QAAQ,IAAI;IACtB,OAAO,EAAE,QAAQ,CAAC;IAClB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,CAAC;IAC5C,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,CAAC,SAAS,EAAE,cAAc,GAAG,SAAS,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,eAAO,MAAM,WAAW,QAAiB,CAAC;AAE1C,MAAM,MAAM,+BAA+B,CAAC,QAAQ,IAAI;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;IACzD,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,GAAG,CAAC,IAAI;IACrD,OAAO,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC;IACtD,QAAQ,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IACpC,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC;IAClD,IAAI,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,wBAAwB,CACnC,QAAQ,CACR,YAAW,4BAA4B,CAAC,QAAQ,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAgC;IAClE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,kBAAkB,CAAS;gBAEvB,OAAO,EAAE,+BAA+B,CAAC,QAAQ,CAAC;IA6B9D,sBAAsB,CACpB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,EAC3C,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAYhC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IA4C1C,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQxD,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,yBAAyB;CAUlC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export const MAX_TIMEOUT = 60 * 60 * 1000; // 1 hour
|
|
2
|
+
export class BlockingBacklogRejection {
|
|
3
|
+
backlogSize;
|
|
4
|
+
getBacklogTimeout;
|
|
5
|
+
queue;
|
|
6
|
+
drainInProgress = false;
|
|
7
|
+
releaseDuringDrain = false;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
const backlogSize = options.backlogSize;
|
|
10
|
+
if (backlogSize !== Number.POSITIVE_INFINITY &&
|
|
11
|
+
(!Number.isFinite(backlogSize) || backlogSize < 0)) {
|
|
12
|
+
throw new RangeError("BlockingBacklogRejection: backlogSize must be a finite number greater than or equal to 0, or Infinity");
|
|
13
|
+
}
|
|
14
|
+
this.backlogSize = backlogSize;
|
|
15
|
+
this.queue = options.queue;
|
|
16
|
+
const backlogTimeout = options.backlogTimeout;
|
|
17
|
+
if (typeof backlogTimeout === "number") {
|
|
18
|
+
this.assertTimeoutWithinBounds(backlogTimeout);
|
|
19
|
+
this.getBacklogTimeout = () => backlogTimeout;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
this.getBacklogTimeout = (context) => {
|
|
23
|
+
const contextTimeout = backlogTimeout(context);
|
|
24
|
+
this.assertTimeoutWithinBounds(contextTimeout);
|
|
25
|
+
return contextTimeout;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
onAllotmentUnavailable(context, retry, signal) {
|
|
29
|
+
if (signal?.aborted) {
|
|
30
|
+
return Promise.resolve(undefined);
|
|
31
|
+
}
|
|
32
|
+
if (this.queue.size() >= this.backlogSize) {
|
|
33
|
+
return Promise.resolve(undefined);
|
|
34
|
+
}
|
|
35
|
+
return this.waitInBacklog(context, retry, signal);
|
|
36
|
+
}
|
|
37
|
+
async onAllotmentReleased() {
|
|
38
|
+
if (this.drainInProgress) {
|
|
39
|
+
this.releaseDuringDrain = true;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (this.queue.size() === 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.drainInProgress = true;
|
|
46
|
+
try {
|
|
47
|
+
while (this.queue.size() > 0) {
|
|
48
|
+
const waiter = this.queue.peekHead();
|
|
49
|
+
if (!waiter) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.releaseDuringDrain = false;
|
|
53
|
+
const allotment = await waiter.retry(waiter.context);
|
|
54
|
+
if (!allotment) {
|
|
55
|
+
if (this.releaseDuringDrain) {
|
|
56
|
+
// A slot was released while retry was in-flight but the
|
|
57
|
+
// notification was suppressed by drainInProgress. Retry the
|
|
58
|
+
// loop so the freed capacity isn't lost.
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!this.queue.removeByHandle(waiter.handle)) {
|
|
64
|
+
// Waiter expired while retry was in-flight. Release the acquired slot
|
|
65
|
+
// so future retries can serve active queued waiters.
|
|
66
|
+
await allotment.releaseAndIgnore();
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
waiter.resolve(allotment);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
this.drainInProgress = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
onLimitChanged(oldLimit, newLimit) {
|
|
77
|
+
if (newLimit > oldLimit) {
|
|
78
|
+
queueMicrotask(() => {
|
|
79
|
+
void this.onAllotmentReleased();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
waitInBacklog(context, retry, signal) {
|
|
84
|
+
const timeout = this.getBacklogTimeout(context);
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
let settled = false;
|
|
87
|
+
const settle = (allotment) => {
|
|
88
|
+
if (settled)
|
|
89
|
+
return;
|
|
90
|
+
settled = true;
|
|
91
|
+
cleanup();
|
|
92
|
+
resolve(allotment);
|
|
93
|
+
};
|
|
94
|
+
const waiter = this.queue.enqueue({
|
|
95
|
+
context,
|
|
96
|
+
retry,
|
|
97
|
+
resolve: (allotment) => settle(allotment),
|
|
98
|
+
});
|
|
99
|
+
const timer = setTimeout(() => settle(undefined), timeout);
|
|
100
|
+
const onAbort = () => settle(undefined);
|
|
101
|
+
const cleanup = () => {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
signal?.removeEventListener("abort", onAbort);
|
|
104
|
+
this.queue.removeByHandle(waiter.handle);
|
|
105
|
+
};
|
|
106
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
assertTimeoutWithinBounds(timeout) {
|
|
110
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
111
|
+
throw new RangeError("Timeout must be a finite number greater than or equal to 0");
|
|
112
|
+
}
|
|
113
|
+
if (timeout > MAX_TIMEOUT) {
|
|
114
|
+
throw new RangeError(`Timeout cannot be greater than ${MAX_TIMEOUT} ms`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LimitAllotment } from "../../LimitAllotment.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { AcquireResult, AllotmentUnavailableStrategy } from "../../Limiter.js";
|
|
3
3
|
import type { DelayedRejectStrategy } from "./DelayedRejectStrategy.js";
|
|
4
4
|
/**
|
|
5
5
|
* Composes "delay then reject" backoff with blocking behavior. On rejection:
|
|
@@ -15,5 +15,6 @@ export declare class DelayedThenBlockingRejection<ContextT> implements Allotment
|
|
|
15
15
|
});
|
|
16
16
|
onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<LimitAllotment | undefined>;
|
|
17
17
|
onAllotmentReleased(): Promise<void>;
|
|
18
|
+
onLimitChanged(oldLimit: number, newLimit: number): void;
|
|
18
19
|
}
|
|
19
20
|
//# sourceMappingURL=DelayedThenBlockingRejection.d.ts.map
|
package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DelayedThenBlockingRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"DelayedThenBlockingRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EACV,aAAa,EACb,4BAA4B,EAC7B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE;;;;GAIG;AACH,qBAAa,4BAA4B,CACvC,QAAQ,CACR,YAAW,4BAA4B,CAAC,QAAQ,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAChE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAyC;gBAE9D,OAAO,EAAE;QACnB,aAAa,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAC/C,gBAAgB,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC;KAC1D;IAKK,sBAAsB,CAC1B,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,EAC3C,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAkBhC,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAK1C,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAGzD"}
|
|
@@ -16,11 +16,19 @@ export class DelayedThenBlockingRejection {
|
|
|
16
16
|
return undefined;
|
|
17
17
|
}
|
|
18
18
|
const allotment = await retry(context);
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
if (allotment) {
|
|
20
|
+
return allotment;
|
|
21
|
+
}
|
|
22
|
+
if (signal?.aborted) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return this.blockingStrategy.onAllotmentUnavailable(context, retry, signal);
|
|
21
26
|
}
|
|
22
27
|
async onAllotmentReleased() {
|
|
23
28
|
await this.delayStrategy.onAllotmentReleased();
|
|
24
29
|
await this.blockingStrategy.onAllotmentReleased();
|
|
25
30
|
}
|
|
31
|
+
onLimitChanged(oldLimit, newLimit) {
|
|
32
|
+
this.blockingStrategy.onLimitChanged?.(oldLimit, newLimit);
|
|
33
|
+
}
|
|
26
34
|
}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { AcquireResult, AllotmentUnavailableStrategy } from "../../Limiter.js";
|
|
2
|
+
export type FifoBlockingRejectionOptions<ContextT> = {
|
|
3
|
+
/**
|
|
4
|
+
* Maximum number of blocked callers in the backlog.
|
|
5
|
+
* Default: unbounded
|
|
6
|
+
*/
|
|
7
|
+
backlogSize?: number | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Maximum timeout for callers blocked on the limiter, in milliseconds.
|
|
10
|
+
* Can be a fixed number or a function that derives the timeout from the
|
|
11
|
+
* request context (e.g. from a deadline). Default: 3_600_000 (1 hour).
|
|
12
|
+
*/
|
|
13
|
+
backlogTimeout?: number | ((context: ContextT) => number) | undefined;
|
|
14
|
+
};
|
|
3
15
|
/**
|
|
4
16
|
* Rejection strategy that blocks the caller in a FIFO queue when the limit
|
|
5
17
|
* has been reached, waiting for a slot to open up. This strategy favors
|
|
@@ -9,18 +21,10 @@ import type { AllotmentUnavailableStrategy, AcquireResult } from "../../Limiter.
|
|
|
9
21
|
* that resolves when a token becomes available.
|
|
10
22
|
*/
|
|
11
23
|
export declare class FifoBlockingRejection<ContextT> implements AllotmentUnavailableStrategy<ContextT> {
|
|
12
|
-
private readonly
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* Default: 3_600_000 (1 hour).
|
|
18
|
-
*/
|
|
19
|
-
timeout?: number | undefined;
|
|
20
|
-
});
|
|
21
|
-
onAllotmentUnavailable(_context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<LimitAllotment | undefined>;
|
|
22
|
-
onAllotmentReleased(): void;
|
|
23
|
-
private acquireAsync;
|
|
24
|
-
private waitForRelease;
|
|
24
|
+
private readonly delegate;
|
|
25
|
+
constructor(options?: FifoBlockingRejectionOptions<ContextT>);
|
|
26
|
+
onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<import("../../LimitAllotment.js").LimitAllotment | undefined>;
|
|
27
|
+
onAllotmentReleased(): Promise<void>;
|
|
28
|
+
onLimitChanged(oldLimit: number, newLimit: number): void;
|
|
25
29
|
}
|
|
26
30
|
//# sourceMappingURL=FifoBlockingRejection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FifoBlockingRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/FifoBlockingRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"FifoBlockingRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/FifoBlockingRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,4BAA4B,EAC7B,MAAM,kBAAkB,CAAC;AAO1B,MAAM,MAAM,4BAA4B,CAAC,QAAQ,IAAI;IACnD;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CACvE,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,qBAAqB,CAChC,QAAQ,CACR,YAAW,4BAA4B,CAAC,QAAQ,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;gBAElD,OAAO,GAAE,4BAA4B,CAAC,QAAQ,CAAM;IAQhE,sBAAsB,CACpB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,EAC3C,MAAM,CAAC,EAAE,WAAW;IAKtB,mBAAmB;IAInB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAGzD"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
2
|
+
import { BlockingBacklogRejection, MAX_TIMEOUT, } from "./BlockingBacklogRejection.js";
|
|
2
3
|
/**
|
|
3
4
|
* Rejection strategy that blocks the caller in a FIFO queue when the limit
|
|
4
5
|
* has been reached, waiting for a slot to open up. This strategy favors
|
|
@@ -8,70 +9,21 @@ const MAX_TIMEOUT = 60 * 60 * 1000; // 1 hour
|
|
|
8
9
|
* that resolves when a token becomes available.
|
|
9
10
|
*/
|
|
10
11
|
export class FifoBlockingRejection {
|
|
11
|
-
|
|
12
|
-
waiters = [];
|
|
12
|
+
delegate;
|
|
13
13
|
constructor(options = {}) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
this.delegate = new BlockingBacklogRejection({
|
|
15
|
+
backlogSize: options.backlogSize ?? Number.POSITIVE_INFINITY,
|
|
16
|
+
backlogTimeout: options.backlogTimeout ?? MAX_TIMEOUT,
|
|
17
|
+
queue: new LinkedWaiterQueue("back"),
|
|
18
|
+
});
|
|
19
19
|
}
|
|
20
|
-
onAllotmentUnavailable(
|
|
21
|
-
return this.
|
|
20
|
+
onAllotmentUnavailable(context, retry, signal) {
|
|
21
|
+
return this.delegate.onAllotmentUnavailable(context, retry, signal);
|
|
22
22
|
}
|
|
23
23
|
onAllotmentReleased() {
|
|
24
|
-
|
|
25
|
-
for (const waiter of waiters) {
|
|
26
|
-
waiter();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
async acquireAsync(context, retry, signal) {
|
|
30
|
-
const deadline = performance.now() + this.timeout;
|
|
31
|
-
while (true) {
|
|
32
|
-
const remaining = deadline - performance.now();
|
|
33
|
-
if (remaining <= 0) {
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
if (signal?.aborted) {
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
const allotment = await retry(context);
|
|
40
|
-
if (allotment) {
|
|
41
|
-
return allotment;
|
|
42
|
-
}
|
|
43
|
-
const acquired = await this.waitForRelease(remaining, signal);
|
|
44
|
-
if (!acquired) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
24
|
+
return this.delegate.onAllotmentReleased();
|
|
48
25
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return Promise.resolve(false);
|
|
52
|
-
}
|
|
53
|
-
return new Promise((resolve) => {
|
|
54
|
-
let settled = false;
|
|
55
|
-
const settle = (acquired) => {
|
|
56
|
-
if (settled)
|
|
57
|
-
return;
|
|
58
|
-
settled = true;
|
|
59
|
-
cleanup();
|
|
60
|
-
resolve(acquired);
|
|
61
|
-
};
|
|
62
|
-
const waiter = () => settle(true);
|
|
63
|
-
this.waiters.push(waiter);
|
|
64
|
-
const timer = setTimeout(() => settle(false), timeoutMs);
|
|
65
|
-
const onAbort = () => settle(false);
|
|
66
|
-
const cleanup = () => {
|
|
67
|
-
clearTimeout(timer);
|
|
68
|
-
signal?.removeEventListener("abort", onAbort);
|
|
69
|
-
const idx = this.waiters.indexOf(waiter);
|
|
70
|
-
if (idx !== -1) {
|
|
71
|
-
this.waiters.splice(idx, 1);
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
75
|
-
});
|
|
26
|
+
onLimitChanged(oldLimit, newLimit) {
|
|
27
|
+
this.delegate.onLimitChanged(oldLimit, newLimit);
|
|
76
28
|
}
|
|
77
29
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { AllotmentUnavailableStrategy, AcquireResult } from "../../Limiter.js";
|
|
1
|
+
import type { AcquireResult, AllotmentUnavailableStrategy } from "../../Limiter.js";
|
|
3
2
|
export interface LifoBlockingRejectionOptions<ContextT> {
|
|
4
3
|
/**
|
|
5
4
|
* Maximum number of blocked callers in the backlog. Default: 100
|
|
@@ -19,13 +18,10 @@ export interface LifoBlockingRejectionOptions<ContextT> {
|
|
|
19
18
|
* latencies low and minimizing timeouts.
|
|
20
19
|
*/
|
|
21
20
|
export declare class LifoBlockingRejection<ContextT> implements AllotmentUnavailableStrategy<ContextT> {
|
|
22
|
-
private readonly
|
|
23
|
-
private readonly getBacklogTimeout;
|
|
24
|
-
private readonly backlog;
|
|
25
|
-
private retry;
|
|
21
|
+
private readonly delegate;
|
|
26
22
|
constructor(options?: LifoBlockingRejectionOptions<ContextT>);
|
|
27
|
-
onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<LimitAllotment | undefined>;
|
|
23
|
+
onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<import("../../LimitAllotment.js").LimitAllotment | undefined>;
|
|
28
24
|
onAllotmentReleased(): Promise<void>;
|
|
29
|
-
|
|
25
|
+
onLimitChanged(oldLimit: number, newLimit: number): void;
|
|
30
26
|
}
|
|
31
27
|
//# sourceMappingURL=LifoBlockingRejection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LifoBlockingRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/LifoBlockingRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"LifoBlockingRejection.d.ts","sourceRoot":"","sources":["../../../src/limiter/allocation-unavailable-strategies/LifoBlockingRejection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,4BAA4B,EAC7B,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,4BAA4B,CAAC,QAAQ;IACpD;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CACvE;AAED;;;;;GAKG;AACH,qBAAa,qBAAqB,CAChC,QAAQ,CACR,YAAW,4BAA4B,CAAC,QAAQ,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;gBAElD,OAAO,GAAE,4BAA4B,CAAC,QAAQ,CAAM;IAQhE,sBAAsB,CACpB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,EAC3C,MAAM,CAAC,EAAE,WAAW;IAKtB,mBAAmB;IAInB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAGzD"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
2
|
+
import { BlockingBacklogRejection, } from "./BlockingBacklogRejection.js";
|
|
1
3
|
/**
|
|
2
4
|
* Rejection strategy that blocks the caller in a LIFO queue when the limit
|
|
3
5
|
* has been reached. This strategy favors availability over latency by
|
|
@@ -5,59 +7,21 @@
|
|
|
5
7
|
* latencies low and minimizing timeouts.
|
|
6
8
|
*/
|
|
7
9
|
export class LifoBlockingRejection {
|
|
8
|
-
|
|
9
|
-
getBacklogTimeout;
|
|
10
|
-
backlog = [];
|
|
11
|
-
retry;
|
|
10
|
+
delegate;
|
|
12
11
|
constructor(options = {}) {
|
|
13
|
-
this.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
this.delegate = new BlockingBacklogRejection({
|
|
13
|
+
backlogSize: options.backlogSize ?? 100,
|
|
14
|
+
backlogTimeout: options.backlogTimeout ?? 1_000,
|
|
15
|
+
queue: new LinkedWaiterQueue("front"),
|
|
16
|
+
});
|
|
17
17
|
}
|
|
18
18
|
onAllotmentUnavailable(context, retry, signal) {
|
|
19
|
-
this.retry
|
|
20
|
-
if (this.backlog.length >= this.backlogSize) {
|
|
21
|
-
return Promise.resolve(undefined);
|
|
22
|
-
}
|
|
23
|
-
return this.waitForBacklog(context, signal);
|
|
19
|
+
return this.delegate.onAllotmentUnavailable(context, retry, signal);
|
|
24
20
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return;
|
|
28
|
-
const waiter = this.backlog[0];
|
|
29
|
-
const allotment = await this.retry(waiter.context);
|
|
30
|
-
if (allotment) {
|
|
31
|
-
this.backlog.shift();
|
|
32
|
-
waiter.resolve(allotment);
|
|
33
|
-
}
|
|
21
|
+
onAllotmentReleased() {
|
|
22
|
+
return this.delegate.onAllotmentReleased();
|
|
34
23
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let settled = false;
|
|
38
|
-
const settle = (allotment) => {
|
|
39
|
-
if (settled)
|
|
40
|
-
return;
|
|
41
|
-
settled = true;
|
|
42
|
-
cleanup();
|
|
43
|
-
resolve(allotment);
|
|
44
|
-
};
|
|
45
|
-
const waiter = {
|
|
46
|
-
context,
|
|
47
|
-
resolve: (allotment) => settle(allotment),
|
|
48
|
-
};
|
|
49
|
-
this.backlog.unshift(waiter);
|
|
50
|
-
const timer = setTimeout(() => settle(undefined), this.getBacklogTimeout(context));
|
|
51
|
-
const onAbort = () => settle(undefined);
|
|
52
|
-
const cleanup = () => {
|
|
53
|
-
clearTimeout(timer);
|
|
54
|
-
signal?.removeEventListener("abort", onAbort);
|
|
55
|
-
const idx = this.backlog.indexOf(waiter);
|
|
56
|
-
if (idx !== -1) {
|
|
57
|
-
this.backlog.splice(idx, 1);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
61
|
-
});
|
|
24
|
+
onLimitChanged(oldLimit, newLimit) {
|
|
25
|
+
this.delegate.onLimitChanged(oldLimit, newLimit);
|
|
62
26
|
}
|
|
63
27
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Limiter, type LimiterOptions } from "../../Limiter.js";
|
|
2
|
+
import { type FifoBlockingRejectionOptions } from "../allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
2
3
|
export declare function makeBlockingLimiter<ContextT = void>(options?: {
|
|
3
|
-
|
|
4
|
+
backlogSize?: number;
|
|
5
|
+
backlogTimeout?: FifoBlockingRejectionOptions<ContextT>["backlogTimeout"];
|
|
4
6
|
limiter?: Omit<LimiterOptions<ContextT>, "allotmentUnavailableStrategy">;
|
|
5
7
|
}): Limiter<ContextT>;
|
|
6
8
|
//# sourceMappingURL=makeBlockingLimiter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makeBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"makeBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makeBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,+DAA+D,CAAC;AAEvE,wBAAgB,mBAAmB,CAAC,QAAQ,GAAG,IAAI,EACjD,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC1E,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,8BAA8B,CAAC,CAAC;CACrE,GACL,OAAO,CAAC,QAAQ,CAAC,CAQnB"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Limiter, } from "../../Limiter.js";
|
|
2
|
-
import { FifoBlockingRejection } from "../allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
2
|
+
import { FifoBlockingRejection, } from "../allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
3
3
|
export function makeBlockingLimiter(options = {}) {
|
|
4
4
|
return new Limiter({
|
|
5
5
|
...options.limiter,
|
|
6
6
|
allotmentUnavailableStrategy: new FifoBlockingRejection({
|
|
7
|
-
|
|
7
|
+
backlogSize: options.backlogSize,
|
|
8
|
+
backlogTimeout: options.backlogTimeout,
|
|
8
9
|
}),
|
|
9
10
|
});
|
|
10
11
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Limiter, type LimiterOptions } from "../../Limiter.js";
|
|
2
2
|
import { type LifoBlockingRejectionOptions } from "../allocation-unavailable-strategies/LifoBlockingRejection.js";
|
|
3
3
|
export declare function makeLifoBlockingLimiter<ContextT = void>(options?: {
|
|
4
|
-
backlogSize?:
|
|
4
|
+
backlogSize?: LifoBlockingRejectionOptions<ContextT>["backlogSize"];
|
|
5
5
|
backlogTimeout?: LifoBlockingRejectionOptions<ContextT>["backlogTimeout"];
|
|
6
6
|
limiter?: Omit<LimiterOptions<ContextT>, "allotmentUnavailableStrategy">;
|
|
7
7
|
}): Limiter<ContextT>;
|