Skip to content

2756. Query Batching

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
type QueryMultipleFn = (keys: string[]) => Promise<string[]>;

type ThrottledRequest = {
  key: string;
  resolve: (result: string) => void;
};

class QueryBatcher {
  private readonly queryMultiple: QueryMultipleFn;
  private readonly throttleTime: number;
  private isThrottling: boolean;
  private throttledRequests: ThrottledRequest[];

  constructor(queryMultiple: QueryMultipleFn, t: number) {
    this.queryMultiple = queryMultiple;
    this.throttleTime = t;
    this.isThrottling = false;
    this.throttledRequests = [];
  }

  async getValue(key: string): Promise<string> {
    if (this.throttleTime === 0) {
      const results = await this.queryMultiple([key]);
      return results[0];
    }
    if (this.isThrottling) {
      return new Promise<string>((resolve) => {
        this.throttledRequests.push({ key, resolve });
      });
    }
    this.isThrottling = true;
    setTimeout(() => this.deThrottle(), this.throttleTime);
    const results = await this.queryMultiple([key]);
    return results[0];
  }

  // De-throttles and processes any pending requests.
  private deThrottle(): void {
    const throttledRequests = this.throttledRequests;
    if (throttledRequests.length === 0) {
      this.isThrottling = false;
    } else {
      const keys = throttledRequests.map((req) => req.key);
      this.queryMultiple(keys).then((results) => {
        results.forEach((result, index) => {
          throttledRequests[index].resolve(result);
        });
      });
      setTimeout(() => this.deThrottle(), this.throttleTime);
      this.throttledRequests = [];
    }
  }
}