Comments (7)
Any update on this?
Stopping websocket dropping is going to be a big issue for a lot of people - surely this should be more of a priority to fix?
from ethers.js.
#1053 seems like it was a fix for ethers v5. Do we have a fix for v6? I was looking at putting up a PR with a fix I've been using in a fork but did not want to duplicate work
from ethers.js.
I've found a way to implement that old solution on v6
:
import { Networkish, WebSocketProvider } from "ethers";
import WebSocket from "ws";
const EXPECTED_PONG_BACK = 15000;
const KEEP_ALIVE_CHECK_INTERVAL = 60 * 1000; //7500;
const debug = (message: string) => {
console.debug(new Date().toISOString(), message);
};
export const ResilientWebsocket = (
url: string,
network: Networkish,
task: (provider: WebSocketProvider) => void
) => {
let terminate = false;
let pingTimeout: NodeJS.Timeout | null = null;
let keepAliveInterval: NodeJS.Timeout | null = null;
let ws: WebSocket | null;
const sleep = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
const startConnection = () => {
ws = new WebSocket(url);
ws.on("open", async () => {
keepAliveInterval = setInterval(() => {
if (!ws) {
debug("No websocket, exiting keep alive interval");
return;
}
debug("Checking if the connection is alive, sending a ping");
ws.ping();
// Use `WebSocket#terminate()`, which immediately destroys the connection,
// instead of `WebSocket#close()`, which waits for the close timer.
// Delay should be equal to the interval at which your server
// sends out pings plus a conservative assumption of the latency.
pingTimeout = setTimeout(() => {
if (ws) ws.terminate();
}, EXPECTED_PONG_BACK);
}, KEEP_ALIVE_CHECK_INTERVAL);
const wsp = new WebSocketProvider(() => ws!, network);
while (ws?.readyState !== WebSocket.OPEN) {
debug("Waiting for websocket to be open");
await sleep(1000);
}
wsp._start();
while (!wsp.ready) {
debug("Waiting for websocket provider to be ready");
await sleep(1000);
}
task(wsp);
});
ws.on("close", () => {
console.error("The websocket connection was closed");
if (keepAliveInterval) clearInterval(keepAliveInterval);
if (pingTimeout) clearTimeout(pingTimeout);
if (!terminate) startConnection();
});
ws.on("pong", () => {
debug("Received pong, so connection is alive, clearing the timeout");
if (pingTimeout) clearTimeout(pingTimeout);
});
return ws;
};
startConnection();
return () => {
terminate = true;
if (keepAliveInterval) clearInterval(keepAliveInterval);
if (pingTimeout) clearTimeout(pingTimeout);
if (ws) {
ws.removeAllListeners();
ws.terminate();
}
};
};
Usage:
terminate = ResilientWebsocket(
WEBSOCKET_URL,
Number(CHAIN_ID),
async (provider) => {
console.log("connected");
}
);
So, you can terminate your process anytime using terminate();
Edit: fixed with @antoinefarley coment: #4251 (comment)
from ethers.js.
@iquirino Your solution works for our setup, although
ws.on("pong", () => { debug("Received pong, so connection is alive, clearing the timeout"); if (pingTimeout) clearInterval(pingTimeout); });should be replaced with:
ws.on("pong", () => { debug("Received pong, so connection is alive, clearing the timeout"); if (pingTimeout) clearTimeout(pingTimeout); });
Hey @antoinefarley, thank you for your reply, I've fixed my last comment with the right code to prevent people from copy wrong code.
So, the correct to work with the v6 is:
import { Networkish, WebSocketProvider } from "ethers";
import WebSocket from "ws";
const EXPECTED_PONG_BACK = 15000;
const KEEP_ALIVE_CHECK_INTERVAL = 60 * 1000; //7500;
const debug = (message: string) => {
console.debug(new Date().toISOString(), message);
};
export const ResilientWebsocket = (
url: string,
network: Networkish,
task: (provider: WebSocketProvider) => void
) => {
let terminate = false;
let pingTimeout: NodeJS.Timeout | null = null;
let keepAliveInterval: NodeJS.Timeout | null = null;
let ws: WebSocket | null;
const sleep = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
const startConnection = () => {
ws = new WebSocket(url);
ws.on("open", async () => {
keepAliveInterval = setInterval(() => {
if (!ws) {
debug("No websocket, exiting keep alive interval");
return;
}
debug("Checking if the connection is alive, sending a ping");
ws.ping();
// Use `WebSocket#terminate()`, which immediately destroys the connection,
// instead of `WebSocket#close()`, which waits for the close timer.
// Delay should be equal to the interval at which your server
// sends out pings plus a conservative assumption of the latency.
pingTimeout = setTimeout(() => {
if (ws) ws.terminate();
}, EXPECTED_PONG_BACK);
}, KEEP_ALIVE_CHECK_INTERVAL);
const wsp = new WebSocketProvider(() => ws!, network);
while (ws?.readyState !== WebSocket.OPEN) {
debug("Waiting for websocket to be open");
await sleep(1000);
}
wsp._start();
while (!wsp.ready) {
debug("Waiting for websocket provider to be ready");
await sleep(1000);
}
task(wsp);
});
ws.on("close", () => {
console.error("The websocket connection was closed");
if (keepAliveInterval) clearInterval(keepAliveInterval);
if (pingTimeout) clearTimeout(pingTimeout);
if (!terminate) startConnection();
});
ws.on("pong", () => {
debug("Received pong, so connection is alive, clearing the timeout");
if (pingTimeout) clearTimeout(pingTimeout);
});
return ws;
};
startConnection();
return () => {
terminate = true;
if (keepAliveInterval) clearInterval(keepAliveInterval);
if (pingTimeout) clearTimeout(pingTimeout);
if (ws) {
ws.removeAllListeners();
ws.terminate();
}
};
};
Usage:
terminate = ResilientWebsocket(
WEBSOCKET_URL,
Number(CHAIN_ID),
async (provider) => {
console.log("connected");
}
);
So, you can terminate your process anytime using terminate();
from ethers.js.
+1
from ethers.js.
#1053 seems like it was a fix for ethers v5. Do we have a fix for v6? I was looking at putting up a PR with a fix I've been using in a fork but did not want to duplicate work
Can you share your fork with the solution?
from ethers.js.
@iquirino Your solution works for our setup, although
ws.on("pong", () => {
debug("Received pong, so connection is alive, clearing the timeout");
if (pingTimeout) clearInterval(pingTimeout);
});
should be replaced with:
ws.on("pong", () => {
debug("Received pong, so connection is alive, clearing the timeout");
if (pingTimeout) clearTimeout(pingTimeout);
});
from ethers.js.
Related Issues (20)
- Await on Transaction Submission Waits for Confirmation HOT 11
- Missing r argument after submit transaction in metamask HOT 2
- deployTransaction property is undefined after contract deployment HOT 1
- estimateGas does not support eip-4844. HOT 4
- Tuple return values from contract calls cannot be used as parameters in subsequent calls. HOT 1
- ProviderError: the method has been deprecated: eth_accounts
- mnemonic.computeSeed is not a function (hdwallet.js:318:48) HOT 3
- Error: invalid value for value.data HOT 1
- Unsigned ethers v6 type 2 transaction HOT 4
- Incorrect EIP712 hashed data with array type
- unknown fragment HOT 1
- Expose encodeFunctionData and decodeFunctionResult as properties on the contract method HOT 1
- Property 'utils' does not exist on type 'typeof
- After the network is switched, the latest provider cannot be obtained HOT 2
- returns code BAD_DATA instead of INSUFFICIENT_FUNDS HOT 1
- Should return code TIMEOUT instead of UNKNOWN_ERROR HOT 1
- 'contract runner does not support calling' error HOT 1
- Not able to resolve module `@adraffy/ens-normalize`
- could not detect network (event="noNetwork", code=NETWORK_ERROR, version=providers/5.7.2)
- QuickNodeProvider does not work HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ethers.js.