I'm trying to create a RetryProvider function that will initialize a connection, send a request to an RPC endpoint, and if the response is not valid (due to rate limits, bad url, etc), increment the URL index of rpcUrls by 1 and tries again with the next URL.
import { ethers } from "ethers";
const rpcUrls = {
1: {
0: "https://badurl.eth.com/rpc",
1: "https://rpc.ankr.com/eth/5b280...",
2: "https://go.getblock.io/01941...",
3: "https://lb.nodies.app/v1/5e9daed36...",
4: "https://eth-mainnet.public.blastapi.io",
5: "https://ethereum.publicnode.com",
6: "https://eth-mainnet.g.alchemy.com/v2/SoDlWkD...",
},
};
class RetryJsonRpcProvider extends ethers.JsonRpcProvider {
constructor(rpcUrls, chainId) {
super(rpcUrls[0], chainId);
this.rpcUrls = rpcUrls;
this.currentIndex = 0;
this.chainId = chainId;
}
async send(method, params) {
try {
console.log(
`Attempting request with URL: ${this.rpcUrls[this.currentIndex]}`
);
return await super.send(method, params);
} catch (error) {
console.log(
`Request failed for URL: ${this.rpcUrls[this.currentIndex]}. Reason: ${
error.message
}`
);
this.currentIndex++;
if (this.currentIndex >= this.rpcUrls.length) {
console.log("All RPC URLs failed.");
throw new Error("All RPC URLs failed.");
} else {
console.log(
`Retrying with next URL: ${this.rpcUrls[this.currentIndex]}`
);
// Recreate the provider with the next URL
const nextProvider = new ethers.JsonRpcProvider(
this.rpcUrls[this.currentIndex],
this.chainId
);
return nextProvider.send(method, params);
}
}
}
}
function createRetryProvider(chainId) {
const urls = Object.values(rpcUrls[chainId]);
return new RetryJsonRpcProvider(urls, chainId);
}
export const providers = {
1: createRetryProvider(1),
56: createRetryProvider(56),
137: createRetryProvider(137),
42161: createRetryProvider(42161),
10: createRetryProvider(10),
8453: createRetryProvider(8453),
};
and I'm getting this response.
Attempting request with URL: https://badurl.eth.com/rpc
Attempting request with URL: https://badurl.eth.com/rpc
Request failed for URL: https://badurl.eth.com/rpc. Reason: getaddrinfo ENOTFOUND badurl.eth.com
Retrying with next URL: https://rpc.ankr.com/eth/5b280c7544a...
Request failed for URL: https://rpc.ankr.com/eth/5b280c7544a... Reason: getaddrinfo ENOTFOUND badurl.eth.com
Retrying with next URL: https://go.getblock.io/019412da1d9...
Attempting request with URL: https://go.getblock.io/019412da1d9...
Attempting request with URL: https://go.getblock.io/019412da1d9...
Request failed for URL: https://go.getblock.io/019412da1d9... Reason: getaddrinfo ENOTFOUND badurl.eth.com
Retrying with next URL: https://lb.nodies.app/v1/5e9daed367d145...
Request failed for URL: https://lb.nodies.app/v1/5e9daed367d145.... Reason: getaddrinfo ENOTFOUND badurl.eth.com
Retrying with next URL: https://eth-mainnet.public.blastapi.io
Attempting request with URL: https://eth-mainnet.public.blastapi.io
Attempting request with URL: https://eth-mainnet.public.blastapi.io
Request failed for URL: https://eth-mainnet.public.blastapi.io. Reason: getaddrinfo ENOTFOUND badurl.eth.com
Retrying with next URL: https://ethereum.publicnode.com
Request failed for URL: https://ethereum.publicnode.com. Reason: getaddrinfo ENOTFOUND badurl.eth.com
Retrying with next URL: https://eth-mainnet.g.alchemy.com/v2/SoD...
It appears that once the initial URL fails, it tries to increment the URL by 1, but still shows an error for the failing URL.
- The end goal is that when the first URL fails, it correctly checks the next URL in the index
- each URL DOES work when used by itself, so I know its not an RPC connection error
- It seems like its not incrementing the URLs appropriately because each URL fails with an error related to the badurl.eth.com address.
- I know this is more of a general JS question, but any help would be really appreciated
- oh, and I'm calling
providersexternally viaprovider = providers[chainId]
Sharing a simple approach I made that achieve:
Giving a list of rpcs