Skip to content

Instantly share code, notes, and snippets.

@WilfredAlmeida
Last active May 16, 2024 13:57
Show Gist options
  • Save WilfredAlmeida/9adea27abb5958178c4370c5656e89b7 to your computer and use it in GitHub Desktop.
Save WilfredAlmeida/9adea27abb5958178c4370c5656e89b7 to your computer and use it in GitHub Desktop.
Using Axios for JSON RPC calls instead of fetch
// This is a custom fetch function that uses axios to make requests and retries on errors or 502 status codes
// Run this file by executing `npx tsx axiosFetchWithRetries.ts`
import { Connection } from "@solana/web3.js";
import axios from "axios";
const RETRY_ATTEMPTS = 3;
const agent = new https.Agent({
maxSockets: 100,
});
const axiosObject = axios.create({
httpsAgent: agent,
});
export async function axiosFetchWithRetries(
input: string | URL | globalThis.Request,
init?: RequestInit,
retryAttempts = 0
): Promise<Response> {
let attempt = 0;
// Adding default headers
if (!init || !init.headers) {
init = {
headers: {
"Content-Type": "application/json",
},
...init,
};
}
while (attempt < retryAttempts) {
try {
let axiosHeaders = {};
axiosHeaders = Array.from(new Headers(init.headers).entries()).reduce(
(acc, [key, value]) => {
acc[key] = value;
return acc;
},
{}
);
const axiosConfig = {
data: init.body,
headers: axiosHeaders,
method: init.method,
baseURL: input.toString(),
validateStatus: (status) => true,
};
const axiosResponse = await axiosObject.request(axiosConfig);
const { data, status, statusText, headers } = axiosResponse;
// Mapping headers from axios to fetch format
const headersArray: [string, string][] = Object.entries(headers).map(
([key, value]) => [key, value]
);
const fetchHeaders = new Headers(headersArray);
const response = new Response(JSON.stringify(data), {
status,
statusText,
headers: fetchHeaders,
});
// Comment the above lines and uncomment the following one to switch from axios to fetch
// const response = await fetch(input, init);
// Traffic might get routed to backups or node restarts or if anything throws a 502, retry
if (response.status === 502) {
console.log("Retrying due to 502");
attempt++;
// Backoff to avoid hammering the server
await new Promise<void>((resolve) =>
setTimeout(resolve, 100 * attempt)
);
continue;
}
return Promise.resolve(response);
} catch (e) {
console.log(`Retrying due to error ${e}`, e);
attempt++;
continue;
}
}
return Promise.reject("Max retries reached");
}
async function main() {
const connection = new Connection("https://api.devnet.solana.com", {
async fetch(input, init?) {
console.log(
"Custom fetch function",
input,
init.method,
init.body,
init.headers
);
return await axiosFetchWithRetries(input, init, RETRY_ATTEMPTS);
},
});
const blockhash = await connection.getLatestBlockhash();
console.log("LATEST BLOCKHASH");
console.log(blockhash);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment