add caching of responses (for 5mins)
Some checks failed
Publish Docker Images / docker (push) Failing after 7s

This commit is contained in:
Lee 2023-11-16 15:54:59 +00:00
parent 355a76845e
commit 6b08b8fc7a
5 changed files with 75 additions and 8 deletions

@ -26,7 +26,6 @@ export default class ProxyRoute extends Route {
res.status(400).json(RouteMessages.badRequest("No URL provided")); res.status(400).json(RouteMessages.badRequest("No URL provided"));
return; return;
} }
// TODO: handle rate limiting? and/or caching?
try { try {
const response = await axios.get(url, { const response = await axios.get(url, {
headers: { headers: {

@ -17,6 +17,7 @@
"server": "workspace:*", "server": "workspace:*",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"utils": "workspace:*" "utils": "workspace:*",
"node-cache": "^5.1.2"
} }
} }

@ -1,9 +1,41 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import Cache from "node-cache";
import { Route, RouteMessages } from "server"; import { Route, RouteMessages } from "server";
import { nodeManager } from ".."; import { nodeManager } from "..";
const IGNORED_PATHS = ["/favicon.ico"]; const IGNORED_PATHS = ["/favicon.ico"];
const cache = new Cache({
stdTTL: 300, // 5 minutes
});
type CachedRequest = {
nodeId: string;
status: number;
headers: any;
data: any;
};
/**
* Logs a request
*
* @param nodeId the node ID that handled the request
* @param url the URL of the request
* @param status the status code of the request
* @param time the time it took to handle the request (or true if it was cached)
*/
function log(
nodeId: string,
url: string,
status: number,
time: number | boolean
) {
console.log(
`[node: ${nodeId}] ${url} - ${status} (${
time === true ? "cached" : time + "ms"
})`
);
}
export default class ProxyRoute extends Route { export default class ProxyRoute extends Route {
constructor() { constructor() {
super({ path: "/" }); super({ path: "/" });
@ -29,8 +61,19 @@ export default class ProxyRoute extends Route {
} }
try { try {
const cachedRequest = cache.get<CachedRequest>(url);
if (cachedRequest) {
log(cachedRequest.nodeId, url, cachedRequest.status, true);
res
.status(cachedRequest.status)
.set(cachedRequest.headers)
.json(cachedRequest.data);
return;
}
const before = Date.now(); const before = Date.now();
const response = await node.fetch(url); const response = await node.fetch(url);
const nodeId = response.headers["x-proxy-node"];
const data = response.data; const data = response.data;
if (response.status === 500) { if (response.status === 500) {
@ -38,15 +81,16 @@ export default class ProxyRoute extends Route {
return; return;
} }
// Log the request log(nodeId, url, response.status, Date.now() - before);
console.log(
`[node: ${response.headers["x-proxy-node"]}] ${url} - ${
response.status
} (${Date.now() - before}ms)`
);
// Return the JSON response // Return the JSON response
res.status(response.status).set(response.headers).json(data); res.status(response.status).set(response.headers).json(data);
cache.set(url, {
nodeId: nodeId,
status: response.status,
headers: response.headers,
data: data,
} as CachedRequest);
} catch (ex: any) { } catch (ex: any) {
res.status(500).json(RouteMessages.internalServerError(ex.message || ex)); res.status(500).json(RouteMessages.internalServerError(ex.message || ex));
} }

@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"infisical-node": "^1.5.0", "infisical-node": "^1.5.0",
"node-cache": "^5.1.2",
"tsup": "^7.2.0" "tsup": "^7.2.0"
} }
} }

22
pnpm-lock.yaml generated

@ -14,6 +14,9 @@ importers:
infisical-node: infisical-node:
specifier: ^1.5.0 specifier: ^1.5.0
version: 1.5.0 version: 1.5.0
node-cache:
specifier: ^5.1.2
version: 5.1.2
tsup: tsup:
specifier: ^7.2.0 specifier: ^7.2.0
version: 7.2.0 version: 7.2.0
@ -75,6 +78,9 @@ importers:
server: server:
specifier: workspace:* specifier: workspace:*
version: link:../../packages/server version: link:../../packages/server
timed-cache:
specifier: ^2.0.0
version: 2.0.0
ts-node: ts-node:
specifier: ^10.9.1 specifier: ^10.9.1
version: 10.9.1(@types/node@20.5.2)(typescript@5.2.2) version: 10.9.1(@types/node@20.5.2)(typescript@5.2.2)
@ -1414,6 +1420,11 @@ packages:
escape-string-regexp: 1.0.5 escape-string-regexp: 1.0.5
dev: true dev: true
/clone@2.1.2:
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
engines: {node: '>=0.8'}
dev: false
/color-convert@1.9.3: /color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies: dependencies:
@ -3287,6 +3298,13 @@ packages:
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
dev: false dev: false
/node-cache@5.1.2:
resolution: {integrity: sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==}
engines: {node: '>= 8.0.0'}
dependencies:
clone: 2.1.2
dev: false
/node-releases@2.0.13: /node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
dev: true dev: true
@ -4096,6 +4114,10 @@ packages:
any-promise: 1.3.0 any-promise: 1.3.0
dev: false dev: false
/timed-cache@2.0.0:
resolution: {integrity: sha512-9owe3VtDCtZKo8bfk5bSC4tSzIRP65doXI0i2oFWNP4VjQDwoRIsADynZQZz6XXK7exL7bOuI3HExFQ9LGi3tQ==}
dev: false
/titleize@3.0.0: /titleize@3.0.0:
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
engines: {node: '>=12'} engines: {node: '>=12'}