From f5c1755666a5d3ace8cd54f1ca84d52761fdc7df Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Mon, 20 May 2024 19:07:06 +0100 Subject: [PATCH] chore: latency naming convention and timeout --- src/services/rpc-service.ts | 77 +++++++++++++-------------------- src/services/storage-service.ts | 20 ++++++--- 2 files changed, 44 insertions(+), 53 deletions(-) diff --git a/src/services/rpc-service.ts b/src/services/rpc-service.ts index 1d36a52..674c6eb 100644 --- a/src/services/rpc-service.ts +++ b/src/services/rpc-service.ts @@ -1,5 +1,5 @@ -import { ValidBlockData } from "../handler"; -import { StorageService } from "./storage-service"; +import { ValidBlockData } from "../../types/handler"; +import axios from "axios"; type PromiseResult = { success: boolean; rpcUrl: string; duration: number }; export class RPCService { @@ -9,92 +9,73 @@ export class RPCService { runtimeRpcs: string[], rpcHeader: object, rpcBody: string, - env: string + rpcTimeout: number ): Promise<{ latencies: Record; runtimeRpcs: string[] }> { + const instance = axios.create({ + timeout: rpcTimeout, + headers: rpcHeader, + cancelToken: new axios.CancelToken((c) => setTimeout(() => c("Request Timeout"), rpcTimeout)), + }); + const successfulPromises = runtimeRpcs.map>( (rpcUrl) => new Promise((resolve) => { - const abortController = new AbortController(); const startTime = performance.now(); - const timeoutId = setTimeout(() => { - abortController.abort(); - resolve({ rpcUrl, success: false, duration: 0 }); - }, 500); - - fetch(rpcUrl, { - method: "POST", - headers: Object.assign({}, rpcHeader, { "Content-Type": "application/json" }), - body: rpcBody, - signal: abortController.signal, - }) + instance + .post(rpcUrl, rpcBody) .then(() => { - clearTimeout(timeoutId); const endTime = performance.now(); resolve({ rpcUrl, duration: endTime - startTime, success: true, - } as PromiseResult); + }); }) .catch(() => { - clearTimeout(timeoutId); resolve({ rpcUrl, success: false, duration: 0 }); }); }) ); - const fastest = await Promise.race(successfulPromises); if (fastest.success) { - latencies[`${fastest.rpcUrl}_${networkId}`] = fastest.duration; + latencies[`${networkId}__${fastest.rpcUrl}`] = fastest.duration; } - try { - const allResults = await Promise.allSettled(successfulPromises); + const allResults = await Promise.allSettled(successfulPromises); - allResults.forEach((result) => { - if (result.status === "fulfilled" && (result.value as PromiseResult).success) { - latencies[`${(result.value as PromiseResult).rpcUrl}_${networkId}`] = (result.value as PromiseResult).duration; - } else if (result.status === "fulfilled") { - const fulfilledResult = result.value as PromiseResult; - const index = runtimeRpcs.indexOf(fulfilledResult.rpcUrl); - if (index > -1) { - runtimeRpcs.splice(index, 1); - } + allResults.forEach((result) => { + if (result.status === "fulfilled" && (result.value as PromiseResult).success) { + latencies[`${networkId}__${(result.value as PromiseResult).rpcUrl}`] = (result.value as PromiseResult).duration; + } else if (result.status === "fulfilled") { + const fulfilledResult = result.value as PromiseResult; + const index = runtimeRpcs.indexOf(fulfilledResult.rpcUrl); + if (index > -1) { + runtimeRpcs.splice(index, 1); } - }); - - StorageService.setLatencies(env, latencies); + } + }); - return { latencies, runtimeRpcs }; - } catch (err) { - console.error("[RPCService] Failed to test RPC performance"); - } return { latencies, runtimeRpcs }; } - - static async findFastestRpc(latencies: Record, networkId: number): Promise { - if (Object.keys(latencies).length === 0) { - console.error("[RPCService] Latencies object is empty"); - } - + static async findFastestRpc(latencies: Record, networkId: number): Promise { try { const validLatencies: Record = Object.entries(latencies) - .filter(([key]) => key.endsWith(`_${networkId}`)) + .filter(([key]) => key.startsWith(`${networkId}__`)) .reduce( (acc, [key, value]) => { acc[key] = value; return acc; }, {} as Record - ); // Add index signature for validLatencies object + ); return Object.keys(validLatencies) .reduce((a, b) => (validLatencies[a] < validLatencies[b] ? a : b)) - .split("_")[0]; + .split("__")[1]; } catch (error) { console.error("[RPCService] Failed to find fastest RPC"); - return ""; + return null; } } diff --git a/src/services/storage-service.ts b/src/services/storage-service.ts index ff486f5..752d0e1 100644 --- a/src/services/storage-service.ts +++ b/src/services/storage-service.ts @@ -1,7 +1,13 @@ export class StorageService { - static getLatencies(env: string): Record { + static getLatencies(env: string, networkId: number): Record { if (env === "browser") { - return JSON.parse(localStorage.getItem("rpcLatencies") || "{}"); + const latencies: Record = JSON.parse(localStorage.getItem("rpcLatencies") || "{}"); + return Object.keys(latencies).reduce((acc: Record, key) => { + if (key.startsWith(`${networkId}__`)) { + acc[key] = latencies[key]; + } + return acc; + }, {}); } return {}; @@ -9,17 +15,21 @@ export class StorageService { static getRefreshLatencies(env: string): number { if (env === "browser") { - return JSON.parse(localStorage.getItem("refreshLatencies") || "0"); + const refresh = JSON.parse(localStorage.getItem("refreshLatencies") || "0"); + + if (typeof refresh === "number") { + return refresh; + } else { + return 0; + } } return 0; } - static setLatencies(env: string, latencies: Record): void { if (env === "browser") { localStorage.setItem("rpcLatencies", JSON.stringify(latencies)); } } - static setRefreshLatencies(env: string, refreshLatencies: number): void { if (env === "browser") { localStorage.setItem("refreshLatencies", JSON.stringify(refreshLatencies));