adaptive-concurrency 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Limiter.d.ts +3 -2
- package/dist/Limiter.d.ts.map +1 -1
- package/dist/Limiter.js +71 -12
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.d.ts +16 -28
- package/dist/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.d.ts.map +1 -1
- package/dist/limiter/allocation-unavailable-strategies/BlockingBacklogRejection.js +33 -90
- package/dist/limiter/allocation-unavailable-strategies/DelayedRejectStrategy.d.ts +1 -1
- package/dist/limiter/allocation-unavailable-strategies/DelayedRejectStrategy.js +1 -1
- package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.d.ts +1 -0
- package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.d.ts.map +1 -1
- package/dist/limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.js +4 -2
- package/dist/limiter/allocation-unavailable-strategies/FifoBlockingRejection.js +3 -2
- package/dist/limiter/allocation-unavailable-strategies/LifoBlockingRejection.js +3 -2
- package/dist/limiter/factories/makeBlockingLimiter.d.ts +1 -2
- package/dist/limiter/factories/makeBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makeBlockingLimiter.js +7 -5
- package/dist/limiter/factories/makeLifoBlockingLimiter.d.ts +2 -3
- package/dist/limiter/factories/makeLifoBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makeLifoBlockingLimiter.js +6 -4
- package/dist/limiter/factories/makePartitionedBlockingLimiter.d.ts +2 -3
- package/dist/limiter/factories/makePartitionedBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makePartitionedBlockingLimiter.js +6 -4
- package/dist/limiter/factories/makePartitionedLifoBlockingLimiter.d.ts +1 -2
- package/dist/limiter/factories/makePartitionedLifoBlockingLimiter.d.ts.map +1 -1
- package/dist/limiter/factories/makePartitionedLifoBlockingLimiter.js +8 -6
- package/dist/utils/LinkedWaiterQueue.d.ts +25 -0
- package/dist/utils/LinkedWaiterQueue.d.ts.map +1 -0
- package/dist/utils/LinkedWaiterQueue.js +85 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/Limiter.d.ts
CHANGED
|
@@ -67,8 +67,9 @@ export interface AllotmentUnavailableStrategy<ContextT> {
|
|
|
67
67
|
*/
|
|
68
68
|
onAllotmentReleased(): MaybePromise<void>;
|
|
69
69
|
/**
|
|
70
|
-
* Called when the adaptive limit changes. Blocking strategies can
|
|
71
|
-
* proactively
|
|
70
|
+
* Called when the adaptive limit changes. Blocking/rejection strategies can
|
|
71
|
+
* use this to proactively react to newly available capacity (e.g. drain
|
|
72
|
+
* backlog).
|
|
72
73
|
*/
|
|
73
74
|
onLimitChanged?(oldLimit: number, newLimit: number): MaybePromise<void>;
|
|
74
75
|
}
|
package/dist/Limiter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Limiter.d.ts","sourceRoot":"","sources":["../src/Limiter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAGL,iBAAiB,EACjB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;AAEhE,MAAM,WAAW,cAAc,CAAC,QAAQ,GAAG,IAAI;IAC7C,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAMD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAAC,QAAQ;IACvC;;;;OAIG;IACH,mBAAmB,CACjB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,YAAY,GAClB,YAAY,CAAC,OAAO,CAAC,CAAC;IAEzB;;;OAGG;IACH,mBAAmB,CAAC,OAAO,EAAE,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAE3D;;;OAGG;IACH,cAAc,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3D;AAED;;;;;GAKG;AACH,MAAM,WAAW,4BAA4B,CAAC,QAAQ;IACpD;;;;;;;;;;OAUG;IACH,sBAAsB,CACpB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,EAC3C,MAAM,CAAC,EAAE,WAAW,GACnB,aAAa,CAAC;IAEjB;;;OAGG;IACH,mBAAmB,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;IAE1C
|
|
1
|
+
{"version":3,"file":"Limiter.d.ts","sourceRoot":"","sources":["../src/Limiter.ts"],"names":[],"mappings":"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"}
|
package/dist/Limiter.js
CHANGED
|
@@ -85,15 +85,27 @@ export class Limiter {
|
|
|
85
85
|
};
|
|
86
86
|
if (!(await this.acquireStrategy.tryAcquireAllotment(ctx, state))) {
|
|
87
87
|
this.rejectedCounter.increment();
|
|
88
|
-
if (this.rejectionStrategy) {
|
|
88
|
+
if (!this.rejectionStrategy) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
// if signal aborted here, nothing to cleanup, as we didn't acquire anything.
|
|
92
|
+
if (options?.signal?.aborted) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
return this.rejectionStrategy.onAllotmentUnavailable(ctx, async (retryCtx) => {
|
|
89
96
|
if (options?.signal?.aborted) {
|
|
90
97
|
return undefined;
|
|
91
98
|
}
|
|
92
|
-
return this.
|
|
93
|
-
}
|
|
99
|
+
return this.tryAcquireCore(retryCtx);
|
|
100
|
+
}, options?.signal);
|
|
101
|
+
}
|
|
102
|
+
const allotment = this.createAllotment(ctx);
|
|
103
|
+
if (options?.signal?.aborted) {
|
|
104
|
+
// here, we did acquire, so we need to try to cleanup.
|
|
105
|
+
await allotment.releaseAndIgnore();
|
|
94
106
|
return undefined;
|
|
95
107
|
}
|
|
96
|
-
return
|
|
108
|
+
return allotment;
|
|
97
109
|
}
|
|
98
110
|
async tryAcquireCore(ctx) {
|
|
99
111
|
const state = {
|
|
@@ -108,30 +120,77 @@ export class Limiter {
|
|
|
108
120
|
createAllotment(ctx) {
|
|
109
121
|
const startTime = this.clock();
|
|
110
122
|
const currentInflight = ++this._inflight;
|
|
123
|
+
// Make sure an allotment can only be released once; future calls become a
|
|
124
|
+
// no-op. This simplifies a lot of cleanup handling etc that'd otherwise be
|
|
125
|
+
// much racier/more complicated. It could hide subtle correctness issue, but
|
|
126
|
+
// should be more valuable as defense-in-depth.
|
|
127
|
+
let releaseStarted = false;
|
|
111
128
|
return {
|
|
112
129
|
releaseAndRecordSuccess: async () => {
|
|
130
|
+
if (releaseStarted)
|
|
131
|
+
return;
|
|
132
|
+
releaseStarted = true;
|
|
113
133
|
const endTime = this.clock();
|
|
114
134
|
const rtt = endTime - startTime;
|
|
115
135
|
this._inflight--;
|
|
116
|
-
await this.acquireStrategy.onAllotmentReleased(ctx);
|
|
117
136
|
this.successCounter.increment();
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
// If one onAllotmentReleased call fails, hard to know what to do here.
|
|
138
|
+
// We're in some kind of inconsistent state, but we probably have to
|
|
139
|
+
// soldier on.
|
|
140
|
+
try {
|
|
141
|
+
await this.acquireStrategy.onAllotmentReleased(ctx);
|
|
142
|
+
}
|
|
143
|
+
catch { }
|
|
144
|
+
try {
|
|
145
|
+
this.limitAlgorithm.addSample(startTime, rtt, currentInflight, false);
|
|
146
|
+
}
|
|
147
|
+
catch { }
|
|
148
|
+
try {
|
|
149
|
+
await this.rejectionStrategy?.onAllotmentReleased();
|
|
150
|
+
}
|
|
151
|
+
catch { }
|
|
120
152
|
},
|
|
121
153
|
releaseAndIgnore: async () => {
|
|
154
|
+
if (releaseStarted)
|
|
155
|
+
return;
|
|
156
|
+
releaseStarted = true;
|
|
122
157
|
this._inflight--;
|
|
123
|
-
await this.acquireStrategy.onAllotmentReleased(ctx);
|
|
124
158
|
this.ignoredCounter.increment();
|
|
125
|
-
|
|
159
|
+
// If one onAllotmentReleased call fails, hard to know what to do here.
|
|
160
|
+
// We're in some kind of inconsistent state, but we probably have to
|
|
161
|
+
// soldier on.
|
|
162
|
+
try {
|
|
163
|
+
await this.acquireStrategy.onAllotmentReleased(ctx);
|
|
164
|
+
}
|
|
165
|
+
catch { }
|
|
166
|
+
try {
|
|
167
|
+
await this.rejectionStrategy?.onAllotmentReleased();
|
|
168
|
+
}
|
|
169
|
+
catch { }
|
|
126
170
|
},
|
|
127
171
|
releaseAndRecordDropped: async () => {
|
|
172
|
+
if (releaseStarted)
|
|
173
|
+
return;
|
|
174
|
+
releaseStarted = true;
|
|
128
175
|
const endTime = this.clock();
|
|
129
176
|
const rtt = endTime - startTime;
|
|
130
177
|
this._inflight--;
|
|
131
|
-
await this.acquireStrategy.onAllotmentReleased(ctx);
|
|
132
178
|
this.droppedCounter.increment();
|
|
133
|
-
|
|
134
|
-
|
|
179
|
+
// If one onAllotmentReleased call fails, hard to know what to do here.
|
|
180
|
+
// We're in some kind of inconsistent state, but we probably have to
|
|
181
|
+
// soldier on.
|
|
182
|
+
try {
|
|
183
|
+
await this.acquireStrategy.onAllotmentReleased(ctx);
|
|
184
|
+
}
|
|
185
|
+
catch { }
|
|
186
|
+
try {
|
|
187
|
+
this.limitAlgorithm.addSample(startTime, rtt, currentInflight, true);
|
|
188
|
+
}
|
|
189
|
+
catch { }
|
|
190
|
+
try {
|
|
191
|
+
await this.rejectionStrategy?.onAllotmentReleased();
|
|
192
|
+
}
|
|
193
|
+
catch { }
|
|
135
194
|
},
|
|
136
195
|
};
|
|
137
196
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,8 +21,7 @@ export { squareRoot, squareRootWithBaseline } from "./utils/index.js";
|
|
|
21
21
|
export * from "./limiter/factories/index.js";
|
|
22
22
|
export { PartitionedStrategy, type PartitionConfig, } from "./limiter/acquire-strategies/PartitionedStrategy.js";
|
|
23
23
|
export { SemaphoreStrategy } from "./limiter/acquire-strategies/SemaphoreStrategy.js";
|
|
24
|
+
export { BlockingBacklogRejection, MAX_TIMEOUT, type BlockingBacklogRejectionOptions, type WaiterQueue, } from "./limiter/allocation-unavailable-strategies/BlockingBacklogRejection.js";
|
|
24
25
|
export { DelayedRejectStrategy, type DelayedRejectStrategyOptions, } from "./limiter/allocation-unavailable-strategies/DelayedRejectStrategy.js";
|
|
25
26
|
export { DelayedThenBlockingRejection } from "./limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.js";
|
|
26
|
-
export { FifoBlockingRejection } from "./limiter/allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
27
|
-
export { LifoBlockingRejection, type LifoBlockingRejectionOptions, } from "./limiter/allocation-unavailable-strategies/LifoBlockingRejection.js";
|
|
28
27
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,OAAO,EACP,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,oBAAoB,EACpB,OAAO,EACP,MAAM,EACN,sBAAsB,EACtB,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,aAAa,EACb,KAAK,qBAAqB,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,GAC1B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAG7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AACxF,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,cAAc,8BAA8B,CAAC;AAG7C,OAAO,EACL,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AAGtF,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,OAAO,EACP,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,4BAA4B,EACjC,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,oBAAoB,EACpB,OAAO,EACP,MAAM,EACN,sBAAsB,EACtB,WAAW,EACX,iBAAiB,EACjB,OAAO,EACP,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,aAAa,EACb,KAAK,qBAAqB,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,GAC1B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAG7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AACxF,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAEtE,cAAc,8BAA8B,CAAC;AAG7C,OAAO,EACL,mBAAmB,EACnB,KAAK,eAAe,GACrB,MAAM,qDAAqD,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mDAAmD,CAAC;AAGtF,OAAO,EACL,wBAAwB,EACxB,WAAW,EACX,KAAK,+BAA+B,EACpC,KAAK,WAAW,GACjB,MAAM,yEAAyE,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,sEAAsE,CAAC;AAC9E,OAAO,EAAE,4BAA4B,EAAE,MAAM,6EAA6E,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,6 @@ export * from "./limiter/factories/index.js";
|
|
|
23
23
|
export { PartitionedStrategy, } from "./limiter/acquire-strategies/PartitionedStrategy.js";
|
|
24
24
|
export { SemaphoreStrategy } from "./limiter/acquire-strategies/SemaphoreStrategy.js";
|
|
25
25
|
// Rejection strategies
|
|
26
|
+
export { BlockingBacklogRejection, MAX_TIMEOUT, } from "./limiter/allocation-unavailable-strategies/BlockingBacklogRejection.js";
|
|
26
27
|
export { DelayedRejectStrategy, } from "./limiter/allocation-unavailable-strategies/DelayedRejectStrategy.js";
|
|
27
28
|
export { DelayedThenBlockingRejection } from "./limiter/allocation-unavailable-strategies/DelayedThenBlockingRejection.js";
|
|
28
|
-
export { FifoBlockingRejection } from "./limiter/allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
29
|
-
export { LifoBlockingRejection, } from "./limiter/allocation-unavailable-strategies/LifoBlockingRejection.js";
|
|
@@ -1,51 +1,39 @@
|
|
|
1
1
|
import type { LimitAllotment } from "../../LimitAllotment.js";
|
|
2
2
|
import type { AcquireResult, AllotmentUnavailableStrategy } from "../../Limiter.js";
|
|
3
|
-
type Waiter<ContextT> = {
|
|
3
|
+
export type Waiter<ContextT> = {
|
|
4
4
|
context: ContextT;
|
|
5
5
|
retry: (context: ContextT) => AcquireResult;
|
|
6
|
-
handle: WaiterHandle;
|
|
7
6
|
resolve: (allotment: LimitAllotment | undefined) => void;
|
|
8
7
|
};
|
|
9
8
|
export declare const MAX_TIMEOUT: number;
|
|
10
|
-
export type BlockingBacklogRejectionOptions<ContextT> = {
|
|
9
|
+
export type BlockingBacklogRejectionOptions<ContextT, Handle> = {
|
|
11
10
|
backlogSize: number;
|
|
12
11
|
backlogTimeout: number | ((context: ContextT) => number);
|
|
13
|
-
queue: WaiterQueue<
|
|
12
|
+
queue: WaiterQueue<ContextT, Handle>;
|
|
14
13
|
};
|
|
15
|
-
export type WaiterQueue<
|
|
16
|
-
enqueue: (waiter:
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
export type WaiterQueue<ContextT, Handle> = {
|
|
15
|
+
enqueue: (waiter: Waiter<ContextT>) => {
|
|
16
|
+
value: Waiter<ContextT>;
|
|
17
|
+
handle: Handle;
|
|
18
|
+
};
|
|
19
|
+
peekHead: () => {
|
|
20
|
+
value: Waiter<ContextT>;
|
|
21
|
+
handle: Handle;
|
|
22
|
+
} | undefined;
|
|
23
|
+
removeByHandle: (handle: Handle) => boolean;
|
|
19
24
|
size: () => number;
|
|
20
25
|
};
|
|
21
|
-
export
|
|
22
|
-
key: symbol;
|
|
23
|
-
};
|
|
24
|
-
export declare class BlockingBacklogRejection<ContextT> implements AllotmentUnavailableStrategy<ContextT> {
|
|
26
|
+
export declare class BlockingBacklogRejection<ContextT, Handle> implements AllotmentUnavailableStrategy<ContextT> {
|
|
25
27
|
private readonly backlogSize;
|
|
26
28
|
private readonly getBacklogTimeout;
|
|
27
29
|
private readonly queue;
|
|
28
30
|
private drainInProgress;
|
|
29
|
-
|
|
31
|
+
private releaseDuringDrain;
|
|
32
|
+
constructor(options: BlockingBacklogRejectionOptions<ContextT, Handle>);
|
|
30
33
|
onAllotmentUnavailable(context: ContextT, retry: (context: ContextT) => AcquireResult, signal?: AbortSignal): Promise<LimitAllotment | undefined>;
|
|
31
34
|
onAllotmentReleased(): Promise<void>;
|
|
32
35
|
onLimitChanged(oldLimit: number, newLimit: number): void;
|
|
33
36
|
private waitInBacklog;
|
|
34
37
|
private assertTimeoutWithinBounds;
|
|
35
38
|
}
|
|
36
|
-
export declare class ArrayWaiterQueue<WaiterT extends Waiter<any>> implements WaiterQueue<WaiterT> {
|
|
37
|
-
private head;
|
|
38
|
-
private tail;
|
|
39
|
-
private readonly nodes;
|
|
40
|
-
private readonly enqueueDirection;
|
|
41
|
-
private length;
|
|
42
|
-
constructor(enqueueDirection: "front" | "back");
|
|
43
|
-
enqueue(waiterWithoutHandle: Omit<WaiterT, "handle">): WaiterT;
|
|
44
|
-
peekHead(): WaiterT | undefined;
|
|
45
|
-
removeByHandle(handle: WaiterHandle): boolean;
|
|
46
|
-
size(): number;
|
|
47
|
-
private pushFront;
|
|
48
|
-
private pushBack;
|
|
49
|
-
}
|
|
50
|
-
export {};
|
|
51
39
|
//# sourceMappingURL=BlockingBacklogRejection.d.ts.map
|
|
@@ -1 +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;AAE1B,
|
|
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;AAE1B,MAAM,MAAM,MAAM,CAAC,QAAQ,IAAI;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,CAAC;IAC5C,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,EAAE,MAAM,IAAI;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;IACzD,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI;IAC1C,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK;QACrC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,MAAM;QAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACxE,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,IAAI,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAEF,qBAAa,wBAAwB,CACnC,QAAQ,EACR,MAAM,CACN,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,EAAE,MAAM,CAAC;IA6BtE,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;IA6C1C,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQxD,OAAO,CAAC,aAAa;IAkCrB,OAAO,CAAC,yBAAyB;CAUlC"}
|
|
@@ -4,8 +4,14 @@ export class BlockingBacklogRejection {
|
|
|
4
4
|
getBacklogTimeout;
|
|
5
5
|
queue;
|
|
6
6
|
drainInProgress = false;
|
|
7
|
+
releaseDuringDrain = false;
|
|
7
8
|
constructor(options) {
|
|
8
|
-
|
|
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;
|
|
9
15
|
this.queue = options.queue;
|
|
10
16
|
const backlogTimeout = options.backlogTimeout;
|
|
11
17
|
if (typeof backlogTimeout === "number") {
|
|
@@ -29,21 +35,33 @@ export class BlockingBacklogRejection {
|
|
|
29
35
|
return this.waitInBacklog(context, retry, signal);
|
|
30
36
|
}
|
|
31
37
|
async onAllotmentReleased() {
|
|
32
|
-
if (this.drainInProgress
|
|
38
|
+
if (this.drainInProgress) {
|
|
39
|
+
this.releaseDuringDrain = true;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (this.queue.size() === 0) {
|
|
33
43
|
return;
|
|
34
44
|
}
|
|
35
45
|
this.drainInProgress = true;
|
|
36
46
|
try {
|
|
37
47
|
while (this.queue.size() > 0) {
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
48
|
+
const queuedWaiter = this.queue.peekHead();
|
|
49
|
+
if (!queuedWaiter) {
|
|
40
50
|
return;
|
|
41
51
|
}
|
|
52
|
+
const waiter = queuedWaiter.value;
|
|
53
|
+
this.releaseDuringDrain = false;
|
|
42
54
|
const allotment = await waiter.retry(waiter.context);
|
|
43
55
|
if (!allotment) {
|
|
56
|
+
if (this.releaseDuringDrain) {
|
|
57
|
+
// A slot was released while retry was in-flight but the
|
|
58
|
+
// notification was suppressed by drainInProgress. Retry the
|
|
59
|
+
// loop so the freed capacity isn't lost.
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
44
62
|
return;
|
|
45
63
|
}
|
|
46
|
-
if (!this.queue.removeByHandle(
|
|
64
|
+
if (!this.queue.removeByHandle(queuedWaiter.handle)) {
|
|
47
65
|
// Waiter expired while retry was in-flight. Release the acquired slot
|
|
48
66
|
// so future retries can serve active queued waiters.
|
|
49
67
|
await allotment.releaseAndIgnore();
|
|
@@ -64,6 +82,7 @@ export class BlockingBacklogRejection {
|
|
|
64
82
|
}
|
|
65
83
|
}
|
|
66
84
|
waitInBacklog(context, retry, signal) {
|
|
85
|
+
const timeout = this.getBacklogTimeout(context);
|
|
67
86
|
return new Promise((resolve) => {
|
|
68
87
|
let settled = false;
|
|
69
88
|
const settle = (allotment) => {
|
|
@@ -73,104 +92,28 @@ export class BlockingBacklogRejection {
|
|
|
73
92
|
cleanup();
|
|
74
93
|
resolve(allotment);
|
|
75
94
|
};
|
|
76
|
-
const waiter =
|
|
95
|
+
const waiter = {
|
|
77
96
|
context,
|
|
78
97
|
retry,
|
|
79
98
|
resolve: (allotment) => settle(allotment),
|
|
80
|
-
}
|
|
81
|
-
const
|
|
99
|
+
};
|
|
100
|
+
const { handle } = this.queue.enqueue(waiter);
|
|
101
|
+
const timer = setTimeout(() => settle(undefined), timeout);
|
|
82
102
|
const onAbort = () => settle(undefined);
|
|
83
103
|
const cleanup = () => {
|
|
84
104
|
clearTimeout(timer);
|
|
85
105
|
signal?.removeEventListener("abort", onAbort);
|
|
86
|
-
this.queue.removeByHandle(
|
|
106
|
+
this.queue.removeByHandle(handle);
|
|
87
107
|
};
|
|
88
108
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
89
109
|
});
|
|
90
110
|
}
|
|
91
111
|
assertTimeoutWithinBounds(timeout) {
|
|
92
|
-
if (timeout
|
|
93
|
-
throw new
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
export class ArrayWaiterQueue {
|
|
98
|
-
head;
|
|
99
|
-
tail;
|
|
100
|
-
nodes = new Map();
|
|
101
|
-
enqueueDirection;
|
|
102
|
-
length = 0;
|
|
103
|
-
constructor(enqueueDirection) {
|
|
104
|
-
this.enqueueDirection = enqueueDirection;
|
|
105
|
-
}
|
|
106
|
-
enqueue(waiterWithoutHandle) {
|
|
107
|
-
const handle = { key: Symbol("waiter-node") };
|
|
108
|
-
const waiter = {
|
|
109
|
-
...waiterWithoutHandle,
|
|
110
|
-
handle,
|
|
111
|
-
};
|
|
112
|
-
const node = {
|
|
113
|
-
handle,
|
|
114
|
-
value: waiter,
|
|
115
|
-
prev: undefined,
|
|
116
|
-
next: undefined,
|
|
117
|
-
};
|
|
118
|
-
this.nodes.set(handle.key, node);
|
|
119
|
-
if (this.enqueueDirection === "front") {
|
|
120
|
-
this.pushFront(node);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
this.pushBack(node);
|
|
112
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
113
|
+
throw new RangeError("Timeout must be a finite number greater than or equal to 0");
|
|
124
114
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
peekHead() {
|
|
129
|
-
return this.head?.value;
|
|
130
|
-
}
|
|
131
|
-
removeByHandle(handle) {
|
|
132
|
-
const node = this.nodes.get(handle.key);
|
|
133
|
-
if (!node)
|
|
134
|
-
return false;
|
|
135
|
-
this.nodes.delete(handle.key);
|
|
136
|
-
if (node.prev) {
|
|
137
|
-
node.prev.next = node.next;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
this.head = node.next;
|
|
141
|
-
}
|
|
142
|
-
if (node.next) {
|
|
143
|
-
node.next.prev = node.prev;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
this.tail = node.prev;
|
|
147
|
-
}
|
|
148
|
-
node.prev = undefined;
|
|
149
|
-
node.next = undefined;
|
|
150
|
-
this.length -= 1;
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
size() {
|
|
154
|
-
return this.length;
|
|
155
|
-
}
|
|
156
|
-
pushFront(node) {
|
|
157
|
-
if (!this.head) {
|
|
158
|
-
this.head = node;
|
|
159
|
-
this.tail = node;
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
node.next = this.head;
|
|
163
|
-
this.head.prev = node;
|
|
164
|
-
this.head = node;
|
|
165
|
-
}
|
|
166
|
-
pushBack(node) {
|
|
167
|
-
if (!this.tail) {
|
|
168
|
-
this.head = node;
|
|
169
|
-
this.tail = node;
|
|
170
|
-
return;
|
|
115
|
+
if (timeout > MAX_TIMEOUT) {
|
|
116
|
+
throw new RangeError(`Timeout cannot be greater than ${MAX_TIMEOUT} ms`);
|
|
171
117
|
}
|
|
172
|
-
node.prev = this.tail;
|
|
173
|
-
this.tail.next = node;
|
|
174
|
-
this.tail = node;
|
|
175
118
|
}
|
|
176
119
|
}
|
|
@@ -16,7 +16,7 @@ export interface DelayedRejectStrategyOptions<ContextT> {
|
|
|
16
16
|
/**
|
|
17
17
|
* When the acquire strategy rejects, waits up to `delayMsForContext(context)`,
|
|
18
18
|
* then still returns no allotment. This adds a form of backpressure. Does not
|
|
19
|
-
* call `retry` — unlike {@link
|
|
19
|
+
* call `retry` — unlike {@link BlockingBacklogRejection}, this is "delay then
|
|
20
20
|
* reject," not "wait for capacity." Compose with `PartitionedStrategy` via
|
|
21
21
|
* `Limiter.rejectionStrategy`; partition delays are not fields on `PartitionConfig`.
|
|
22
22
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* When the acquire strategy rejects, waits up to `delayMsForContext(context)`,
|
|
3
3
|
* then still returns no allotment. This adds a form of backpressure. Does not
|
|
4
|
-
* call `retry` — unlike {@link
|
|
4
|
+
* call `retry` — unlike {@link BlockingBacklogRejection}, this is "delay then
|
|
5
5
|
* reject," not "wait for capacity." Compose with `PartitionedStrategy` via
|
|
6
6
|
* `Limiter.rejectionStrategy`; partition delays are not fields on `PartitionConfig`.
|
|
7
7
|
*/
|
|
@@ -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,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;
|
|
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"}
|
|
@@ -22,11 +22,13 @@ export class DelayedThenBlockingRejection {
|
|
|
22
22
|
if (signal?.aborted) {
|
|
23
23
|
return undefined;
|
|
24
24
|
}
|
|
25
|
-
return (
|
|
26
|
-
this.blockingStrategy.onAllotmentUnavailable(context, retry, signal));
|
|
25
|
+
return this.blockingStrategy.onAllotmentUnavailable(context, retry, signal);
|
|
27
26
|
}
|
|
28
27
|
async onAllotmentReleased() {
|
|
29
28
|
await this.delayStrategy.onAllotmentReleased();
|
|
30
29
|
await this.blockingStrategy.onAllotmentReleased();
|
|
31
30
|
}
|
|
31
|
+
onLimitChanged(oldLimit, newLimit) {
|
|
32
|
+
this.blockingStrategy.onLimitChanged?.(oldLimit, newLimit);
|
|
33
|
+
}
|
|
32
34
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
|
@@ -13,7 +14,7 @@ export class FifoBlockingRejection {
|
|
|
13
14
|
this.delegate = new BlockingBacklogRejection({
|
|
14
15
|
backlogSize: options.backlogSize ?? Number.POSITIVE_INFINITY,
|
|
15
16
|
backlogTimeout: options.backlogTimeout ?? MAX_TIMEOUT,
|
|
16
|
-
queue: new
|
|
17
|
+
queue: new LinkedWaiterQueue("back"),
|
|
17
18
|
});
|
|
18
19
|
}
|
|
19
20
|
onAllotmentUnavailable(context, retry, signal) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
2
|
+
import { BlockingBacklogRejection, } from "./BlockingBacklogRejection.js";
|
|
2
3
|
/**
|
|
3
4
|
* Rejection strategy that blocks the caller in a LIFO queue when the limit
|
|
4
5
|
* has been reached. This strategy favors availability over latency by
|
|
@@ -11,7 +12,7 @@ export class LifoBlockingRejection {
|
|
|
11
12
|
this.delegate = new BlockingBacklogRejection({
|
|
12
13
|
backlogSize: options.backlogSize ?? 100,
|
|
13
14
|
backlogTimeout: options.backlogTimeout ?? 1_000,
|
|
14
|
-
queue: new
|
|
15
|
+
queue: new LinkedWaiterQueue("front"),
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
onAllotmentUnavailable(context, retry, signal) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Limiter, type LimiterOptions } from "../../Limiter.js";
|
|
2
|
-
import { type FifoBlockingRejectionOptions } from "../allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
3
2
|
export declare function makeBlockingLimiter<ContextT = void>(options?: {
|
|
4
3
|
backlogSize?: number;
|
|
5
|
-
backlogTimeout?:
|
|
4
|
+
backlogTimeout?: number | ((context: ContextT) => number);
|
|
6
5
|
limiter?: Omit<LimiterOptions<ContextT>, "allotmentUnavailableStrategy">;
|
|
7
6
|
}): Limiter<ContextT>;
|
|
8
7
|
//# 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,
|
|
1
|
+
{"version":3,"file":"makeBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makeBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAQhE,wBAAgB,mBAAmB,CAAC,QAAQ,GAAG,IAAI,EACjD,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;IAC1D,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,8BAA8B,CAAC,CAAC;CACrE,GACL,OAAO,CAAC,QAAQ,CAAC,CASnB"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { Limiter
|
|
2
|
-
import {
|
|
1
|
+
import { Limiter } from "../../Limiter.js";
|
|
2
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
3
|
+
import { BlockingBacklogRejection, MAX_TIMEOUT, } from "../allocation-unavailable-strategies/BlockingBacklogRejection.js";
|
|
3
4
|
export function makeBlockingLimiter(options = {}) {
|
|
4
5
|
return new Limiter({
|
|
5
6
|
...options.limiter,
|
|
6
|
-
allotmentUnavailableStrategy: new
|
|
7
|
-
backlogSize: options.backlogSize,
|
|
8
|
-
backlogTimeout: options.backlogTimeout,
|
|
7
|
+
allotmentUnavailableStrategy: new BlockingBacklogRejection({
|
|
8
|
+
backlogSize: options.backlogSize ?? Number.POSITIVE_INFINITY,
|
|
9
|
+
backlogTimeout: options.backlogTimeout ?? MAX_TIMEOUT,
|
|
10
|
+
queue: new LinkedWaiterQueue("back"),
|
|
9
11
|
}),
|
|
10
12
|
});
|
|
11
13
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Limiter, type LimiterOptions } from "../../Limiter.js";
|
|
2
|
-
import { type LifoBlockingRejectionOptions } from "../allocation-unavailable-strategies/LifoBlockingRejection.js";
|
|
3
2
|
export declare function makeLifoBlockingLimiter<ContextT = void>(options?: {
|
|
4
|
-
backlogSize?:
|
|
5
|
-
backlogTimeout?:
|
|
3
|
+
backlogSize?: number;
|
|
4
|
+
backlogTimeout?: number | ((context: ContextT) => number);
|
|
6
5
|
limiter?: Omit<LimiterOptions<ContextT>, "allotmentUnavailableStrategy">;
|
|
7
6
|
}): Limiter<ContextT>;
|
|
8
7
|
//# sourceMappingURL=makeLifoBlockingLimiter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makeLifoBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makeLifoBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"makeLifoBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makeLifoBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOhE,wBAAgB,uBAAuB,CAAC,QAAQ,GAAG,IAAI,EACrD,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;IAC1D,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,8BAA8B,CAAC,CAAC;CACrE,GACL,OAAO,CAAC,QAAQ,CAAC,CASnB"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Limiter } from "../../Limiter.js";
|
|
2
|
-
import {
|
|
2
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
3
|
+
import { BlockingBacklogRejection, } from "../allocation-unavailable-strategies/BlockingBacklogRejection.js";
|
|
3
4
|
export function makeLifoBlockingLimiter(options = {}) {
|
|
4
5
|
return new Limiter({
|
|
5
6
|
...options.limiter,
|
|
6
|
-
allotmentUnavailableStrategy: new
|
|
7
|
-
backlogSize: options.backlogSize,
|
|
8
|
-
backlogTimeout: options.backlogTimeout,
|
|
7
|
+
allotmentUnavailableStrategy: new BlockingBacklogRejection({
|
|
8
|
+
backlogSize: options.backlogSize ?? 100,
|
|
9
|
+
backlogTimeout: options.backlogTimeout ?? 1_000,
|
|
10
|
+
queue: new LinkedWaiterQueue("front"),
|
|
9
11
|
}),
|
|
10
12
|
});
|
|
11
13
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Limiter, type LimiterOptions } from "../../Limiter.js";
|
|
2
2
|
import { type PartitionConfig } from "../acquire-strategies/PartitionedStrategy.js";
|
|
3
|
-
import { type FifoBlockingRejectionOptions } from "../allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
4
3
|
export declare function makePartitionedBlockingLimiter<ContextT, PartitionName extends string = string>(options: {
|
|
5
4
|
partitionResolver: (context: ContextT) => PartitionName | undefined;
|
|
6
5
|
partitions: Record<PartitionName, PartitionConfig & {
|
|
@@ -8,7 +7,7 @@ export declare function makePartitionedBlockingLimiter<ContextT, PartitionName e
|
|
|
8
7
|
}>;
|
|
9
8
|
limiter?: Omit<LimiterOptions<ContextT>, "acquireStrategy">;
|
|
10
9
|
maxConcurrentDelays?: number;
|
|
11
|
-
backlogSize?:
|
|
12
|
-
backlogTimeout?:
|
|
10
|
+
backlogSize?: number;
|
|
11
|
+
backlogTimeout?: number | ((context: ContextT) => number);
|
|
13
12
|
}): Limiter<ContextT>;
|
|
14
13
|
//# sourceMappingURL=makePartitionedBlockingLimiter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makePartitionedBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makePartitionedBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"makePartitionedBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makePartitionedBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,8CAA8C,CAAC;AAStD,wBAAgB,8BAA8B,CAC5C,QAAQ,EACR,aAAa,SAAS,MAAM,GAAG,MAAM,EACrC,OAAO,EAAE;IACT,iBAAiB,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,GAAG,SAAS,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,eAAe,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;CAC3D,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkCpB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Limiter } from "../../Limiter.js";
|
|
2
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
2
3
|
import { PartitionedStrategy, } from "../acquire-strategies/PartitionedStrategy.js";
|
|
4
|
+
import { BlockingBacklogRejection, MAX_TIMEOUT, } from "../allocation-unavailable-strategies/BlockingBacklogRejection.js";
|
|
3
5
|
import { DelayedRejectStrategy } from "../allocation-unavailable-strategies/DelayedRejectStrategy.js";
|
|
4
6
|
import { DelayedThenBlockingRejection } from "../allocation-unavailable-strategies/DelayedThenBlockingRejection.js";
|
|
5
|
-
import { FifoBlockingRejection, } from "../allocation-unavailable-strategies/FifoBlockingRejection.js";
|
|
6
7
|
export function makePartitionedBlockingLimiter(options) {
|
|
7
8
|
const limit = options.limiter?.limit ?? Limiter.makeDefaultLimit();
|
|
8
9
|
const delayByPartition = new Map(Object.entries(options.partitions).map(([name, cfg]) => [
|
|
@@ -28,9 +29,10 @@ export function makePartitionedBlockingLimiter(options) {
|
|
|
28
29
|
},
|
|
29
30
|
maxConcurrentDelays: options.maxConcurrentDelays,
|
|
30
31
|
}),
|
|
31
|
-
blockingStrategy: new
|
|
32
|
-
backlogSize: options.backlogSize,
|
|
33
|
-
backlogTimeout: options.backlogTimeout,
|
|
32
|
+
blockingStrategy: new BlockingBacklogRejection({
|
|
33
|
+
backlogSize: options.backlogSize ?? Number.POSITIVE_INFINITY,
|
|
34
|
+
backlogTimeout: options.backlogTimeout ?? MAX_TIMEOUT,
|
|
35
|
+
queue: new LinkedWaiterQueue("back"),
|
|
34
36
|
}),
|
|
35
37
|
}),
|
|
36
38
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Limiter, type LimiterOptions } from "../../Limiter.js";
|
|
2
|
-
import { type LifoBlockingRejectionOptions } from "../allocation-unavailable-strategies/LifoBlockingRejection.js";
|
|
3
2
|
import { type PartitionConfig } from "../acquire-strategies/PartitionedStrategy.js";
|
|
4
3
|
export declare function makePartitionedLifoBlockingLimiter<ContextT, PartitionName extends string = string>(options: {
|
|
5
4
|
partitionResolver: (context: ContextT) => PartitionName | undefined;
|
|
@@ -9,6 +8,6 @@ export declare function makePartitionedLifoBlockingLimiter<ContextT, PartitionNa
|
|
|
9
8
|
limiter?: Omit<LimiterOptions<ContextT>, "acquireStrategy">;
|
|
10
9
|
maxConcurrentDelays?: number;
|
|
11
10
|
backlogSize?: number;
|
|
12
|
-
backlogTimeout?:
|
|
11
|
+
backlogTimeout?: number | ((context: ContextT) => number);
|
|
13
12
|
}): Limiter<ContextT>;
|
|
14
13
|
//# sourceMappingURL=makePartitionedLifoBlockingLimiter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"makePartitionedLifoBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makePartitionedLifoBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"makePartitionedLifoBlockingLimiter.d.ts","sourceRoot":"","sources":["../../../src/limiter/factories/makePartitionedLifoBlockingLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,8CAA8C,CAAC;AAQtD,wBAAgB,kCAAkC,CAChD,QAAQ,EACR,aAAa,SAAS,MAAM,GAAG,MAAM,EACrC,OAAO,EAAE;IACT,iBAAiB,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,aAAa,GAAG,SAAS,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,eAAe,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,OAAO,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;CAC3D,GAAG,OAAO,CAAC,QAAQ,CAAC,CAmCpB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Limiter
|
|
1
|
+
import { Limiter } from "../../Limiter.js";
|
|
2
|
+
import { LinkedWaiterQueue } from "../../utils/LinkedWaiterQueue.js";
|
|
3
|
+
import { PartitionedStrategy, } from "../acquire-strategies/PartitionedStrategy.js";
|
|
4
|
+
import { BlockingBacklogRejection, } from "../allocation-unavailable-strategies/BlockingBacklogRejection.js";
|
|
2
5
|
import { DelayedRejectStrategy } from "../allocation-unavailable-strategies/DelayedRejectStrategy.js";
|
|
3
6
|
import { DelayedThenBlockingRejection } from "../allocation-unavailable-strategies/DelayedThenBlockingRejection.js";
|
|
4
|
-
import { LifoBlockingRejection, } from "../allocation-unavailable-strategies/LifoBlockingRejection.js";
|
|
5
|
-
import { PartitionedStrategy, } from "../acquire-strategies/PartitionedStrategy.js";
|
|
6
7
|
export function makePartitionedLifoBlockingLimiter(options) {
|
|
7
8
|
const limit = options.limiter?.limit ?? Limiter.makeDefaultLimit();
|
|
8
9
|
const delayByPartition = new Map(Object.entries(options.partitions).map(([name, cfg]) => [
|
|
@@ -28,9 +29,10 @@ export function makePartitionedLifoBlockingLimiter(options) {
|
|
|
28
29
|
},
|
|
29
30
|
maxConcurrentDelays: options.maxConcurrentDelays,
|
|
30
31
|
}),
|
|
31
|
-
blockingStrategy: new
|
|
32
|
-
backlogSize: options.backlogSize,
|
|
33
|
-
backlogTimeout: options.backlogTimeout,
|
|
32
|
+
blockingStrategy: new BlockingBacklogRejection({
|
|
33
|
+
backlogSize: options.backlogSize ?? 100,
|
|
34
|
+
backlogTimeout: options.backlogTimeout ?? 1_000,
|
|
35
|
+
queue: new LinkedWaiterQueue("front"),
|
|
34
36
|
}),
|
|
35
37
|
}),
|
|
36
38
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
declare class ItemHandle {
|
|
2
|
+
}
|
|
3
|
+
export type EnqueueDirection = "front" | "back";
|
|
4
|
+
export declare class LinkedWaiterQueue<T extends object> {
|
|
5
|
+
private head;
|
|
6
|
+
private tail;
|
|
7
|
+
private readonly nodes;
|
|
8
|
+
private readonly enqueueDirection;
|
|
9
|
+
private length;
|
|
10
|
+
constructor(enqueueDirection: EnqueueDirection);
|
|
11
|
+
enqueue(value: T, enqueueDirection?: EnqueueDirection): {
|
|
12
|
+
value: T;
|
|
13
|
+
handle: ItemHandle;
|
|
14
|
+
};
|
|
15
|
+
peekHead(): {
|
|
16
|
+
value: T;
|
|
17
|
+
handle: ItemHandle;
|
|
18
|
+
} | undefined;
|
|
19
|
+
removeByHandle(handle: ItemHandle): boolean;
|
|
20
|
+
size(): number;
|
|
21
|
+
private pushFront;
|
|
22
|
+
private pushBack;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=LinkedWaiterQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LinkedWaiterQueue.d.ts","sourceRoot":"","sources":["../../src/utils/LinkedWaiterQueue.ts"],"names":[],"mappings":"AAAA,cAAM,UAAU;CAAG;AAEnB,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAC;AAShD,qBAAa,iBAAiB,CAAC,CAAC,SAAS,MAAM;IAC7C,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAC9D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,MAAM,CAAK;gBAEP,gBAAgB,EAAE,gBAAgB;IAI9C,OAAO,CACL,KAAK,EAAE,CAAC,EACR,gBAAgB,CAAC,EAAE,gBAAgB,GAClC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE;IAqBnC,QAAQ,IAAI;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,GAAG,SAAS;IAUxD,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO;IAuB3C,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,QAAQ;CAWjB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
class ItemHandle {
|
|
2
|
+
}
|
|
3
|
+
export class LinkedWaiterQueue {
|
|
4
|
+
head;
|
|
5
|
+
tail;
|
|
6
|
+
nodes = new Map();
|
|
7
|
+
enqueueDirection;
|
|
8
|
+
length = 0;
|
|
9
|
+
constructor(enqueueDirection) {
|
|
10
|
+
this.enqueueDirection = enqueueDirection;
|
|
11
|
+
}
|
|
12
|
+
enqueue(value, enqueueDirection) {
|
|
13
|
+
const handle = new ItemHandle();
|
|
14
|
+
const node = {
|
|
15
|
+
handle,
|
|
16
|
+
value: value,
|
|
17
|
+
prev: undefined,
|
|
18
|
+
next: undefined,
|
|
19
|
+
};
|
|
20
|
+
const direction = enqueueDirection ?? this.enqueueDirection;
|
|
21
|
+
this.nodes.set(handle, node);
|
|
22
|
+
if (direction === "front") {
|
|
23
|
+
this.pushFront(node);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.pushBack(node);
|
|
27
|
+
}
|
|
28
|
+
this.length += 1;
|
|
29
|
+
return { value, handle };
|
|
30
|
+
}
|
|
31
|
+
peekHead() {
|
|
32
|
+
if (!this.head) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
value: this.head.value,
|
|
37
|
+
handle: this.head.handle,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
removeByHandle(handle) {
|
|
41
|
+
const node = this.nodes.get(handle);
|
|
42
|
+
if (!node)
|
|
43
|
+
return false;
|
|
44
|
+
this.nodes.delete(handle);
|
|
45
|
+
if (node.prev) {
|
|
46
|
+
node.prev.next = node.next;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.head = node.next;
|
|
50
|
+
}
|
|
51
|
+
if (node.next) {
|
|
52
|
+
node.next.prev = node.prev;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
this.tail = node.prev;
|
|
56
|
+
}
|
|
57
|
+
node.prev = undefined;
|
|
58
|
+
node.next = undefined;
|
|
59
|
+
this.length -= 1;
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
size() {
|
|
63
|
+
return this.length;
|
|
64
|
+
}
|
|
65
|
+
pushFront(node) {
|
|
66
|
+
if (!this.head) {
|
|
67
|
+
this.head = node;
|
|
68
|
+
this.tail = node;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
node.next = this.head;
|
|
72
|
+
this.head.prev = node;
|
|
73
|
+
this.head = node;
|
|
74
|
+
}
|
|
75
|
+
pushBack(node) {
|
|
76
|
+
if (!this.tail) {
|
|
77
|
+
this.head = node;
|
|
78
|
+
this.tail = node;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
node.prev = this.tail;
|
|
82
|
+
this.tail.next = node;
|
|
83
|
+
this.tail = node;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GACf,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAEvB"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"dynamic rate limiting"
|
|
10
10
|
],
|
|
11
11
|
"author": "Ethan Resnick <ethan.resnick@gmail.com>",
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.4.0",
|
|
13
13
|
"type": "module",
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
@@ -29,6 +29,6 @@
|
|
|
29
29
|
"tsx": "^4.19.0",
|
|
30
30
|
"type-fest": "^5.5.0",
|
|
31
31
|
"type-party": "^0.7.3",
|
|
32
|
-
"typescript": "
|
|
32
|
+
"typescript": "^6.0.2"
|
|
33
33
|
}
|
|
34
34
|
}
|