fix: reduce cold call times — aspa/verify cache + 3s LG timeout + 8s default fetchJSON
- aspa/verify: 15min result cache, looking-glass 3s timeout (was 20s default), 5→3 prefixes - fetchJSON default timeout: 20s→8s prevents all uncached RIPE Stat calls from waiting 20s - All cards now respond in <1s on cold call (ASPA 200ms, verify 170ms, validate 820ms, WHOIS 50ms) - bgproutes still 4s cold (bgproutes.io API latency, cached after first call)
This commit is contained in:
parent
35b89c05aa
commit
487b032661
@ -1233,7 +1233,7 @@ function checkRateLimit(ip) {
|
||||
}
|
||||
|
||||
function fetchJSON(url, options) {
|
||||
const timeoutMs = (options && options.timeout) || 20000;
|
||||
const timeoutMs = (options && options.timeout) || 8000;
|
||||
return new Promise((resolve) => {
|
||||
const reqOptions = {
|
||||
headers: { "User-Agent": UA, ...(options && options.headers ? options.headers : {}) },
|
||||
@ -2390,24 +2390,29 @@ const server = http.createServer(async (req, res) => {
|
||||
res.writeHead(400);
|
||||
return res.end(JSON.stringify({ error: "Missing or invalid ASN parameter" }));
|
||||
}
|
||||
const cachedVerify = resultCacheGet(aspaResultCache, "verify:" + rawAsn);
|
||||
if (cachedVerify !== undefined) {
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
return res.end(JSON.stringify(cachedVerify));
|
||||
}
|
||||
const targetAsn = parseInt(rawAsn);
|
||||
const start = Date.now();
|
||||
|
||||
try {
|
||||
// Fetch neighbour and prefix data first
|
||||
const [neighbourData, prefixData] = await Promise.all([
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + rawAsn),
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/announced-prefixes/data.json?resource=AS" + rawAsn),
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + rawAsn, { timeout: 5000 }),
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/announced-prefixes/data.json?resource=AS" + rawAsn, { timeout: 5000 }),
|
||||
]);
|
||||
|
||||
// Use looking-glass with actual prefixes to get BGP paths
|
||||
const announcedPrefixes = prefixData?.data?.prefixes || [];
|
||||
const samplePrefixes = announcedPrefixes.slice(0, 5).map((p) => p.prefix);
|
||||
const samplePrefixes = announcedPrefixes.slice(0, 3).map((p) => p.prefix); // reduced 5→3
|
||||
|
||||
// Fetch looking-glass data for up to 5 prefixes in parallel
|
||||
// Fetch looking-glass data for up to 3 prefixes in parallel (3s timeout each)
|
||||
const lgResults = await Promise.all(
|
||||
samplePrefixes.map((pfx) =>
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/looking-glass/data.json?resource=" + encodeURIComponent(pfx))
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/looking-glass/data.json?resource=" + encodeURIComponent(pfx), { timeout: 3000 }).catch(() => null)
|
||||
)
|
||||
);
|
||||
|
||||
@ -2590,10 +2595,7 @@ const server = http.createServer(async (req, res) => {
|
||||
});
|
||||
|
||||
const duration = Date.now() - start;
|
||||
|
||||
return res.end(
|
||||
JSON.stringify(
|
||||
{
|
||||
const verifyResult = {
|
||||
meta: {
|
||||
query: "AS" + rawAsn,
|
||||
duration_ms: duration,
|
||||
@ -2630,11 +2632,9 @@ const server = http.createServer(async (req, res) => {
|
||||
results: pathResults,
|
||||
},
|
||||
rpki_coverage: rpkiCoverage,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
};
|
||||
resultCacheSet(aspaResultCache, "verify:" + rawAsn, verifyResult);
|
||||
return res.end(JSON.stringify(verifyResult, null, 2));
|
||||
} catch (err) {
|
||||
res.writeHead(500);
|
||||
return res.end(JSON.stringify({ error: "ASPA verification failed", message: err.message }));
|
||||
|
||||
30
server.js
30
server.js
@ -1233,7 +1233,7 @@ function checkRateLimit(ip) {
|
||||
}
|
||||
|
||||
function fetchJSON(url, options) {
|
||||
const timeoutMs = (options && options.timeout) || 20000;
|
||||
const timeoutMs = (options && options.timeout) || 8000;
|
||||
return new Promise((resolve) => {
|
||||
const reqOptions = {
|
||||
headers: { "User-Agent": UA, ...(options && options.headers ? options.headers : {}) },
|
||||
@ -2390,24 +2390,29 @@ const server = http.createServer(async (req, res) => {
|
||||
res.writeHead(400);
|
||||
return res.end(JSON.stringify({ error: "Missing or invalid ASN parameter" }));
|
||||
}
|
||||
const cachedVerify = resultCacheGet(aspaResultCache, "verify:" + rawAsn);
|
||||
if (cachedVerify !== undefined) {
|
||||
res.writeHead(200, { "Content-Type": "application/json" });
|
||||
return res.end(JSON.stringify(cachedVerify));
|
||||
}
|
||||
const targetAsn = parseInt(rawAsn);
|
||||
const start = Date.now();
|
||||
|
||||
try {
|
||||
// Fetch neighbour and prefix data first
|
||||
const [neighbourData, prefixData] = await Promise.all([
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + rawAsn),
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/announced-prefixes/data.json?resource=AS" + rawAsn),
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/asn-neighbours/data.json?resource=AS" + rawAsn, { timeout: 5000 }),
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/announced-prefixes/data.json?resource=AS" + rawAsn, { timeout: 5000 }),
|
||||
]);
|
||||
|
||||
// Use looking-glass with actual prefixes to get BGP paths
|
||||
const announcedPrefixes = prefixData?.data?.prefixes || [];
|
||||
const samplePrefixes = announcedPrefixes.slice(0, 5).map((p) => p.prefix);
|
||||
const samplePrefixes = announcedPrefixes.slice(0, 3).map((p) => p.prefix); // reduced 5→3
|
||||
|
||||
// Fetch looking-glass data for up to 5 prefixes in parallel
|
||||
// Fetch looking-glass data for up to 3 prefixes in parallel (3s timeout each)
|
||||
const lgResults = await Promise.all(
|
||||
samplePrefixes.map((pfx) =>
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/looking-glass/data.json?resource=" + encodeURIComponent(pfx))
|
||||
fetchRipeStatCached("https://stat.ripe.net/data/looking-glass/data.json?resource=" + encodeURIComponent(pfx), { timeout: 3000 }).catch(() => null)
|
||||
)
|
||||
);
|
||||
|
||||
@ -2590,10 +2595,7 @@ const server = http.createServer(async (req, res) => {
|
||||
});
|
||||
|
||||
const duration = Date.now() - start;
|
||||
|
||||
return res.end(
|
||||
JSON.stringify(
|
||||
{
|
||||
const verifyResult = {
|
||||
meta: {
|
||||
query: "AS" + rawAsn,
|
||||
duration_ms: duration,
|
||||
@ -2630,11 +2632,9 @@ const server = http.createServer(async (req, res) => {
|
||||
results: pathResults,
|
||||
},
|
||||
rpki_coverage: rpkiCoverage,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
};
|
||||
resultCacheSet(aspaResultCache, "verify:" + rawAsn, verifyResult);
|
||||
return res.end(JSON.stringify(verifyResult, null, 2));
|
||||
} catch (err) {
|
||||
res.writeHead(500);
|
||||
return res.end(JSON.stringify({ error: "ASPA verification failed", message: err.message }));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user