addons/shared/__tests__/RateLimiter.test.tsblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import {RateLimiter} from '../RateLimiter';
b69ab319import {nextTick} from '../testUtils';
b69ab3110import {defer} from '../utils';
b69ab3111
b69ab3112describe('RateLimiter', () => {
b69ab3113 it('immediately invokes if less than max simultaneous requests are running', () => {
b69ab3114 const d1 = defer();
b69ab3115 const d2 = defer();
b69ab3116 const d3 = defer();
b69ab3117 const rateLimiter = new RateLimiter(3);
b69ab3118 let ran1 = false;
b69ab3119 let ran2 = false;
b69ab3120 let ran3 = false;
b69ab3121 rateLimiter.enqueueRun(async () => {
b69ab3122 ran1 = true;
b69ab3123 await d1.promise;
b69ab3124 });
b69ab3125 rateLimiter.enqueueRun(async () => {
b69ab3126 ran2 = true;
b69ab3127 await d2.promise;
b69ab3128 });
b69ab3129 rateLimiter.enqueueRun(async () => {
b69ab3130 ran3 = true;
b69ab3131 await d3.promise;
b69ab3132 });
b69ab3133 expect(ran1).toBe(true);
b69ab3134 expect(ran2).toBe(true);
b69ab3135 expect(ran3).toBe(true);
b69ab3136 });
b69ab3137
b69ab3138 it('queues requests over max simultaneous until a previous task finishes', async () => {
b69ab3139 const d1 = defer();
b69ab3140 const d2 = defer();
b69ab3141 const rateLimiter = new RateLimiter(2);
b69ab3142 rateLimiter.enqueueRun(() => d1.promise);
b69ab3143 rateLimiter.enqueueRun(() => d2.promise);
b69ab3144
b69ab3145 let hasId3Resolved = false;
b69ab3146 rateLimiter
b69ab3147 .enqueueRun(() => Promise.resolve())
b69ab3148 .then(() => {
b69ab3149 hasId3Resolved = true;
b69ab3150 });
b69ab3151 expect(hasId3Resolved).toBe(false);
b69ab3152
b69ab3153 d2.resolve(undefined);
b69ab3154 await nextTick();
b69ab3155 expect(hasId3Resolved).toBe(true);
b69ab3156 });
b69ab3157
b69ab3158 it('can be used as a lock with concurrency limit 1', async () => {
b69ab3159 const d1 = defer();
b69ab3160 const d2 = defer();
b69ab3161 const d3 = defer();
b69ab3162 const rateLimiter = new RateLimiter(1);
b69ab3163 let ran1 = false;
b69ab3164 let ran2 = false;
b69ab3165 let ran3 = false;
b69ab3166 rateLimiter.enqueueRun(async () => {
b69ab3167 await d1.promise;
b69ab3168 ran1 = true;
b69ab3169 });
b69ab3170 rateLimiter.enqueueRun(async () => {
b69ab3171 await d2.promise;
b69ab3172 ran2 = true;
b69ab3173 });
b69ab3174 rateLimiter.enqueueRun(async () => {
b69ab3175 await d3.promise;
b69ab3176 ran3 = true;
b69ab3177 });
b69ab3178
b69ab3179 expect(ran1).toBe(false);
b69ab3180 expect(ran2).toBe(false);
b69ab3181 expect(ran3).toBe(false);
b69ab3182
b69ab3183 d1.resolve(undefined);
b69ab3184 await nextTick();
b69ab3185
b69ab3186 expect(ran1).toBe(true);
b69ab3187 expect(ran2).toBe(false);
b69ab3188 expect(ran3).toBe(false);
b69ab3189
b69ab3190 d2.resolve(undefined);
b69ab3191 await nextTick();
b69ab3192
b69ab3193 expect(ran1).toBe(true);
b69ab3194 expect(ran2).toBe(true);
b69ab3195 expect(ran3).toBe(false);
b69ab3196
b69ab3197 d3.resolve(undefined);
b69ab3198 await nextTick();
b69ab3199
b69ab31100 expect(ran1).toBe(true);
b69ab31101 expect(ran2).toBe(true);
b69ab31102 expect(ran3).toBe(true);
b69ab31103 });
b69ab31104
b69ab31105 it('Handles async work that rejects', async () => {
b69ab31106 const d1 = defer();
b69ab31107 const d2 = defer();
b69ab31108 const rateLimiter = new RateLimiter(2);
b69ab31109 rateLimiter.enqueueRun(() => d1.promise);
b69ab31110 let sawError = false;
b69ab31111 rateLimiter
b69ab31112 .enqueueRun(async () => {
b69ab31113 await d2.promise;
b69ab31114 throw new Error();
b69ab31115 })
b69ab31116 .catch(() => {
b69ab31117 sawError = true;
b69ab31118 });
b69ab31119
b69ab31120 let hasId3Resolved = false;
b69ab31121 rateLimiter
b69ab31122 .enqueueRun(() => Promise.resolve())
b69ab31123 .then(() => {
b69ab31124 hasId3Resolved = true;
b69ab31125 });
b69ab31126 expect(hasId3Resolved).toBe(false);
b69ab31127
b69ab31128 d2.resolve(undefined);
b69ab31129 await nextTick();
b69ab31130 expect(hasId3Resolved).toBe(true);
b69ab31131 expect(sawError).toBe(true);
b69ab31132 });
b69ab31133});