add caching of responses (for 5mins)
Some checks failed
Publish Docker Images / docker (push) Failing after 7s
Some checks failed
Publish Docker Images / docker (push) Failing after 7s
This commit is contained in:
parent
355a76845e
commit
6b08b8fc7a
@ -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
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'}
|
||||||
|
Loading…
Reference in New Issue
Block a user