Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import * as AtomicTimer from "../../../utils/AtomicTimer";
- import { floorToMinutes } from "../../../utils/TimeUtils";
- import { RedisService } from "../RedisService";
- import * as winston from "winston";
- // TODO: unit test the hell outta this
- export class ApiRequestService extends RedisService {
- // Every application may make up to 5000 requests per hour.
- // Request counts are stored in one-minute blocks which get added
- // and removed from a list.
- // expires after 1 hour
- static readonly expiry: number = 60;
- async incrApiRequest(application: string) {
- // first, increment the temporary and total counter
- let temp: number = Number(await this.client.incr("app:${application}:request:tempCounter"));
- await this.client.incr("app:${application}:request:totalCounter");
- await this.update(application, temp);
- }
- async getApiRequests(application: string): Promise<number> {
- let total: number = await this.update(application);
- if (!total) total = Number(await this.client.get("app:${application}:request:totalCounter"));
- return total;
- }
- async update(application: string, temp?: number): Promise<number> {
- // the amount of minutes passed since the unix epoch
- const now: number = floorToMinutes((await AtomicTimer.syncTime()).unix());
- // the last time the list was updated
- const last: number = Number(await this.client.get("app:${application}:request:lastUpdate"));
- const minutesPassed: number = last == 0 ? 0 : now - last;
- // retrieve the temp counter unless provided
- if (!temp) temp = Number(await this.client.get("app:${application}:request:tempCounter"));
- let total: number;
- // if the list has less entries than it should, fill it up
- const llen: number = Number(await this.client.llen("app:${application}:request:list"));
- if (llen < ApiRequestService.expiry) {
- if (llen != 0) winston.warn("Less than %s elements in in request count list for application %s", llen, application);
- for (let i = llen; i < ApiRequestService.expiry; i++) {
- await this.client.rpush("app:${application}:request:list", 0);
- }
- }
- for (let i = 0; i < minutesPassed; i++) {
- // remove the last element of the list and subtract it from the counter
- let c: number = Number(await this.client.lpop("app:${application}:request:list"));
- total = Number(await this.client.decrby("app:${application}:request:totalCounter", c));
- // push the temp counter onto the list and reset it
- await this.client.rpush("app:${application}:request:list", temp);
- await this.client.set("app:${application}:request:tempCounter", 0);
- temp = 0;
- }
- // update the last update time
- await this.client.set("app:${application}:request:lastUpdate", now);
- return total;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment