From 852c907d358c8c7e2076aff752a0d9b5ed59263c Mon Sep 17 00:00:00 2001 From: Kaushik Narayan R Date: Fri, 14 Mar 2025 17:25:23 -0700 Subject: [PATCH] rate limiting --- api/spotify.ts | 22 ++++++++++++++++++++-- package-lock.json | 7 +++++++ package.json | 1 + utils/graph.ts | 8 ++++---- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/api/spotify.ts b/api/spotify.ts index 1a18064..d4b6a1f 100644 --- a/api/spotify.ts +++ b/api/spotify.ts @@ -1,3 +1,5 @@ +import Bottleneck from "bottleneck"; + import { axiosInstance } from "./axios.ts"; import { @@ -50,6 +52,18 @@ type SingleRequestResult = Promise<{ message: string; }>; +const rateLimiter = new Bottleneck({ + // slow start + reservoir: 0, + reservoirIncreaseAmount: 2, + reservoirIncreaseInterval: 1000, + // for bursts + reservoirIncreaseMaximum: 30, + + minTime: 200, + maxConcurrent: 10, +}); + /** * Spotify API (v1) - one-off request handler */ @@ -67,9 +81,13 @@ const singleRequest = async ({ try { if (!data || inlineData) { if (data) config.data = data ?? null; - resp = await axiosInstance[method](path, config); + resp = await rateLimiter.schedule(() => + axiosInstance[method](path, config) + ); } else { - resp = await axiosInstance[method](path, data, config); + resp = await rateLimiter.schedule(() => + axiosInstance[method](path, data, config) + ); } logger.debug(logPrefix + "Successful response received."); return { resp, message: "" }; diff --git a/package-lock.json b/package-lock.json index fc72e58..6ae9ec8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "axios": "^1.8.2", + "bottleneck": "^2.19.5", "connect-redis": "^8.0.1", "cookie-parser": "^1.4.7", "cors": "^2.8.5", @@ -895,6 +896,12 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", diff --git a/package.json b/package.json index f11ccde..734f8f2 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "homepage": "https://github.com/20kaushik02/spotify-manager#readme", "dependencies": { "axios": "^1.8.2", + "bottleneck": "^2.19.5", "connect-redis": "^8.0.1", "cookie-parser": "^1.4.7", "cors": "^2.8.5", diff --git a/utils/graph.ts b/utils/graph.ts index ca02d8f..078721b 100644 --- a/utils/graph.ts +++ b/utils/graph.ts @@ -34,12 +34,12 @@ class myGraph { getDirectHeads(node: GNode): GNode[] { return this.edges - .filter((edge) => edge.to == node) + .filter((edge) => edge.to === node) .map((edge) => edge.from); } getDirectHeadEdges(node: GNode): GEdge[] { - return this.edges.filter((edge) => edge.to == node); + return this.edges.filter((edge) => edge.to === node); } /** BFS */ @@ -61,7 +61,7 @@ class myGraph { getDirectTails(node: GNode): GNode[] { return this.edges - .filter((edge) => edge.from == node) + .filter((edge) => edge.from === node) .map((edge) => edge.to); } @@ -70,7 +70,7 @@ class myGraph { * @returns {{ from: string, to: string }[]} */ getDirectTailEdges(node: GNode): GEdge[] { - return this.edges.filter((edge) => edge.from == node); + return this.edges.filter((edge) => edge.from === node); } /** BFS */