Skip to content

Commit 56a9de8

Browse files
committed
feat(pkg:concurrent): added utility class LeakyBucketRateLimiterManager
1 parent e3b65c1 commit 56a9de8

10 files changed

+626
-150
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- feat(pkg:concurrent): added utility class `TokenBucketRateLimiter`
88
- feat(pkg:concurrent): added utility class `TokenBucketRateLimiterManager`
99
- feat(pkg:concurrent): added utility class `LeakyBucketRateLimiter`
10+
- feat(pkg:concurrent): added utility class `LeakyBucketRateLimiterManager`
1011
- feat(pkg:ts-types): added helper type `IJsonSafeValue`
1112
- feat(pkg:ts-types): added helper type `IMaybeArray`
1213
- feat(pkg:concurrent): added utility class `ManualBreaker`

packages/partials/concurrent/src/Classes/LeakyBucketRateLimiter.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ NodeTest.describe('Class LeakyBucketRateLimiter', async () => {
3838
await autoTick(ctx, limiter.challenge());
3939

4040
const pr = limiter.challenge();
41-
NodeAssert.strictEqual(limiter.isLimited(), true);
41+
NodeAssert.strictEqual(limiter.isBlocking(), true);
4242
// the second one, should wait 100ms.
4343
// The next leaking time should be at 200ms later.
4444
await autoTick(ctx, pr);
@@ -105,7 +105,7 @@ NodeTest.describe('Class LeakyBucketRateLimiter', async () => {
105105
NodeAssert.strictEqual(Date.now() - start, 0);
106106

107107
const pr = limiter.call(() => 'second');
108-
NodeAssert.strictEqual(limiter.isLimited(), true);
108+
NodeAssert.strictEqual(limiter.isBlocking(), true);
109109

110110
// the second one, should wait 100ms.
111111
// The next leaking time should be at 200ms later.
@@ -142,7 +142,7 @@ NodeTest.describe('Class LeakyBucketRateLimiter', async () => {
142142
NodeAssert.strictEqual(Date.now() - start, 0);
143143

144144
const pr = wrapped(10, 20);
145-
NodeAssert.strictEqual(limiter.isLimited(), true);
145+
NodeAssert.strictEqual(limiter.isBlocking(), true);
146146

147147
// the second one, should wait 100ms.
148148
// The next leaking time should be at 200ms later.
@@ -204,7 +204,7 @@ NodeTest.describe('Class LeakyBucketRateLimiter', async () => {
204204

205205
prAllowed.push(limiter.challenge());
206206
prAllowed.push(limiter.challenge());
207-
NodeAssert.strictEqual(limiter.isLimited(), true);
207+
NodeAssert.strictEqual(limiter.isBlocking(), true);
208208
prAllowed.push(NodeAssert.rejects(limiter.challenge()));
209209

210210
limiter.reset();

packages/partials/concurrent/src/Classes/LeakyBucketRateLimiter.ts

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,11 @@ export class LeakyBucketRateLimiter implements IAsyncRateLimiter {
7070
this._errCtor = opts.errorCtorOnLimited ?? E_RATE_LIMITED;
7171
}
7272

73-
/**
74-
* Challenge the rate limiter. If it's limited, an error will be thrown.
75-
* Otherwise, the function will wait until the task is able to be processed.
76-
*/
73+
public isIdle(): boolean {
74+
75+
return this._nextLeakingAt <= Date.now();
76+
}
77+
7778
public async challenge(): Promise<void> {
7879

7980
const ttl = this._leak();
@@ -106,43 +107,23 @@ export class LeakyBucketRateLimiter implements IAsyncRateLimiter {
106107
return elapsed;
107108
}
108109

109-
/**
110-
* Call the given function if the limiter is not limited, or throw an error if
111-
* the limiter is limited.
112-
*
113-
* @param fn The function to be called.
114-
* @returns The return value of the given function.
115-
* @throws An error if the limiter is limited, or if the given function throws an error.
116-
*/
117110
public async call<TFn extends IFunction>(fn: TFn): Promise<Awaited<ReturnType<TFn>>> {
118111

119112
await this.challenge();
120113

121114
return fn() as Awaited<ReturnType<TFn>>;
122115
}
123116

124-
/**
125-
* Reset the internal context.
126-
*/
127117
public reset(): void {
128118

129119
this._nextLeakingAt = Date.now();
130120
}
131121

132-
/**
133-
* Check whether the rate limiter is blocking all access now.
134-
*/
135-
public isLimited(): boolean {
122+
public isBlocking(): boolean {
136123

137124
return this._nextLeakingAt - Date.now() > this._maxWaitMs - this._leakIntervalMs;
138125
}
139126

140-
/**
141-
* Wrap the given function with rate limiting challenge.
142-
*
143-
* @param fn The function to be wrapped.
144-
* @returns The new wrapped function.
145-
*/
146127
public wrap<T extends IFunction>(fn: T): IFunction<Parameters<T>, IToPromise<ReturnType<T>>> {
147128

148129
return (async (...args: unknown[]) => {

0 commit comments

Comments
 (0)