Web3JS Socket/Connection Issues
Dealing with Socket/Connection issues in Web3JS
If you are running high-throughput applications using @solana/web3.js
in a NodeJS environment, you may encounter persistent socket or connection errors, especially under heavy asynchronous load. This guide explains the root cause of these issues and provides several effective solutions.
Common Errors
These errors often manifest with messages like fetch failed
, Connect Timeout Error
, ECONNREFUSED
, ECONNRESET
, or other side closed
. They are a strong indicator that your application is hitting local system limits for network connections.
The Root Cause: Port Exhaustion in NodeJS
These errors are not caused by the RPC node or the @solana/web3.js
library itself. They stem from NodeJS's implementation of fetch
, which uses the undici
HTTP client. By default, undici
aggressively opens a new TCP socket for each outgoing request.
Under heavy, concurrent load, this behavior can quickly exhaust the available ephemeral ports on your operating system, leading to the connection failures you see.
Diagnosing the Issue
You can check how many ports your Node process is using on a UNIX-based system with the following command. A high number (in the thousands) is a clear sign of this issue.
lsof -i -n -P | grep node | awk '{print $9}' | awk -F '->' '{print $1}' | \
awk -F ':' '{print $2}' | sort -u | wc -l
External References
This is a known issue related to connection management in undici
. You can find more context in these community discussions and articles:
Recommended Solutions
The fundamental solution is to stop creating a new connection for every request and instead reuse a pool of connections.
Why Limit Connections?
Establishing a new TCP connection requires a TLS handshake, which is a time-consuming process. More details here. By reusing a smaller pool of persistent connections, your application will be more performant, and it will place significantly less load on both your client machine and our RPC servers.
What Is an Ideal Connection Count?
We recommend starting with a limit of 50 connections. You can monitor your port usage with the lsof
command above. If you see that all 50 connections are consistently in use and your application could benefit, you can gradually increase this limit.
1. Limit Connections with a Global Agent (Recommended)
This is the best solution for most applications. You configure NodeJS to use a global agent with a connection pool, forcing the HTTP client to reuse connections.
For undici
(Node's default fetch
):
Install undici
and set the global dispatcher at the very beginning of your application's entry point.
// At the top of your main application file
import { setGlobalDispatcher, Agent } from "undici";
setGlobalDispatcher(
new Agent({
connections: 50, // Recommended starting default
})
);
For axios
:
If you prefer axios
, you can create a client with a dedicated https.Agent
. The @solana/web3.js
Connection
object allows you to pass a custom fetch implementation. A full example can be found at this Gist.
import https from 'https';
const agent = new https.Agent({
maxSockets: 50, // Recommended starting default
keepAlive: true,
});
const axiosInstance = axios.create({
httpsAgent: agent,
});
2. Use an Alternative Runtime (Bun)
The Bun runtime is a modern alternative to NodeJS. Based on our testing, its internal HTTP client handles connection pooling more efficiently and does not exhibit this socket exhaustion issue. This is a great option for new projects but may be a larger change for existing codebases.
3. Using the new version of `@solana/web3.js`.
Anza Labs is developing a new and improved version of the library which, as of this writing, is in technical preview. It uses the undici
library and the errors are less frequent in it. If encountered, with the configuration mentioned in [1] they should be resolved. Do note that the library is not compatible with the current version, meaning that it’ll be a ground up rewrite of your codebase.
4. A Note on Other Libraries
If you're using SDKs like jito-ts which uses node-fetch underneath, or some other libraries, you may encounter errors like ERR_STREAM_PREMATURE_CLOSE
which have this same underlying issue and limiting the number of connections for NodeJS has resolved the issue for our customers. The number of connections for libraries like node-fetch
and others can be limited by providing an http(s).Agent
configuration. For example
Copy
new https.Agent({
maxSockets: 50,
});
Last updated
Was this helpful?