Skip to content

Instantly share code, notes, and snippets.

@WilfredAlmeida
Last active March 1, 2025 01:56
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();
@WilfredAlmeida
Copy link
Author

Yes I faced this error and thus switched to using axios. This issue has a fix now, check this out
https://docs.triton.one/chains/solana/web3js-socket-connection-issues

@utsavempiric20
Copy link

The Custom function which you write for the RPC connection. are you using it right now or while back?

@utsavempiric20
Copy link

I don't receive the error like this which does not include the cause:

 cause: ConnectTimeoutError: Connect Timeout Error
      at onConnectTimeout (node:internal/deps/undici/undici:6869:28)
      at node:internal/deps/undici/undici:6825:50
      at Immediate._onImmediate (node:internal/deps/undici/undici:6857:13)
      at process.processImmediate (node:internal/timers:478:21) {
    code: 'UND_ERR_CONNECT_TIMEOUT'
  }

i only receive only like below:

TypeError: fetch failed
    at node:internal/deps/undici/undici:12606:11
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
    at runNextTicks (node:internal/process/task_queues:64:3)
    at processImmediate (node:internal/timers:454:9)
    at ClientBrowser.callServer (/var/www/prod/soltrackers/server/node_modules/@solana/web3.js/src/connection.ts:1675:17)

the above error give me a this at ClientBrowser.callServer (/var/www/prod/soltrackers/server/node_modules/@solana/web3.js/src/connection.ts:1675:17) and when i fave this error :TypeError: fetch failed the my script execution stopped. I handle the proper all errors but i don't know from where it occurs. so can you suggest me more about that?

@utsavempiric20
Copy link

utsavempiric20 commented Jan 22, 2025

Thank you @WilfredAlmeida for giving me a solution. the one last question is that in the Documentation you metnion that we need to Configure the undici

import { setGlobalDispatcher, Agent } from "undici";

setGlobalDispatcher(
  new Agent({
    connections: 50,
  })
);

but in above code you didn't mention so is that above script working without the undici package or i need to Configure it?

@WilfredAlmeida
Copy link
Author

Glad it worked. The above script is setting agent and number of connection already

const agent = new https.Agent({
  maxSockets: 100,
});

const axiosObject = axios.create({
  httpsAgent: agent,
});

@utsavempiric20
Copy link

Thank you @WilfredAlmeida for giving me a solution and i like the way you explain each and every things in a simple words in documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment