Skip to content

Commit

Permalink
chore: latency naming convention and timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyrxng committed May 20, 2024
1 parent 87cbcaa commit f5c1755
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 53 deletions.
77 changes: 29 additions & 48 deletions src/services/rpc-service.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -9,92 +9,73 @@ export class RPCService {
runtimeRpcs: string[],
rpcHeader: object,
rpcBody: string,
env: string
rpcTimeout: number
): Promise<{ latencies: Record<string, number>; runtimeRpcs: string[] }> {
const instance = axios.create({
timeout: rpcTimeout,
headers: rpcHeader,
cancelToken: new axios.CancelToken((c) => setTimeout(() => c("Request Timeout"), rpcTimeout)),
});

const successfulPromises = runtimeRpcs.map<Promise<PromiseResult>>(
(rpcUrl) =>
new Promise<PromiseResult>((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<string, number>, networkId: number): Promise<string> {
if (Object.keys(latencies).length === 0) {
console.error("[RPCService] Latencies object is empty");
}

static async findFastestRpc(latencies: Record<string, number>, networkId: number): Promise<string | null> {
try {
const validLatencies: Record<string, number> = Object.entries(latencies)
.filter(([key]) => key.endsWith(`_${networkId}`))
.filter(([key]) => key.startsWith(`${networkId}__`))
.reduce(
(acc, [key, value]) => {
acc[key] = value;
return acc;
},
{} as Record<string, number>
); // 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;
}
}

Expand Down
20 changes: 15 additions & 5 deletions src/services/storage-service.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
export class StorageService {
static getLatencies(env: string): Record<string | number, number> {
static getLatencies(env: string, networkId: number): Record<string | number, number> {
if (env === "browser") {
return JSON.parse(localStorage.getItem("rpcLatencies") || "{}");
const latencies: Record<string, number> = JSON.parse(localStorage.getItem("rpcLatencies") || "{}");
return Object.keys(latencies).reduce((acc: Record<string, number>, key) => {
if (key.startsWith(`${networkId}__`)) {
acc[key] = latencies[key];
}
return acc;
}, {});
}

return {};
}

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<string | number, number>): 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));
Expand Down

0 comments on commit f5c1755

Please sign in to comment.