You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The WebSocket connection to the Ethereum node should remain active. The connection should continuously listen to smart contract events.
Actual behavior
The WebSocket connection to the Ethereum node either closes or becomes idle after some time (approximately 5-6 hours or 10 hours). When this happens, the reconnection attempts fail to listen to smart contract events.
Steps to reproduce the behavior
Run the provided code to initialize the Web3 instance with the WebSocket provider and connect to the Ethereum node.
Subscribe to new block headers and smart contract events.
Keep running the app and observe the logs. After some hours (approximately 5-6 hours or 10 hours) app stops logs subscribeToEthNewBlockHeaders .
Observe that the WebSocket connection either closes or becomes idle, and reconnection attempts fail to listen to smart contract events.
const{ Web3 }=require('web3');constconnectWeb3=async(wsUrl)=>{// https://community.infura.io/t/web3-js-how-to-keep-websocket-subscriptions-alive-and-reconnect-on-failures/6199constprovider=newWeb3(newWeb3.providers.WebsocketProvider(wsUrl,{},{autoReconnect: true,delay: 5000,maxAttempts: 5,}));awaitnewPromise((resolve,reject)=>{provider.currentProvider.on('connect',()=>{ethereumLogger.info(`Connected to Ethereum node at ${wsUrl}`);resolve();});provider.currentProvider.on('error',(error)=>{ethereumLogger.error(`Error while connecting to Ethereum node: ${error}`);reject(error);});});returnprovider;};// Subscribe to new block headersconstsubscribeToEthNewBlockHeaders=async(web3,ethNetwork)=>{constsubscription=awaitweb3.eth.subscribe('newHeads',async(error,result)=>{if(error){ethereumLogger.error(`Error subscribing to new block headers: ${error}`);}else{ethereumLogger.info(`${ethNetwork}:=> New block header received: ${result.number}`);}});subscription.on("data",(blockHeader)=>{ethereumLogger.info(`${ethNetwork}:=> New block header received: ${blockHeader.number}`);});subscription.on("changed",(newSubscription)=>{ethereumLogger.info(`${ethNetwork}:=> Subscription changed: ${newSubscription}`);});subscription.on("error",(error)=>{ethereumLogger.error(`Error subscribing to new block headers: ${error}`);});subscription.on("end",(error,unsubscribe)=>{if(error){ethereumLogger.error(`Error subscribing to new block headers: ${error}`);}else{ethereumLogger.info(`${ethNetwork}:=> Unsubscribed from new block headers: ${unsubscribe}`);}});};// src/listeners/ethListener.jsconst{ loadFile }=require('../utils/fileUtils');const{ checkEnvVars }=require('../utils/checkEnv');const{ ethereumLogger }=require('../utils/logger');const{ connectWeb3, ethNetworkName, subscribeToEthNewBlockHeaders }=require('../utils/ethUtils');const{ handleEthEvents }=require('../events/ethEventHandlers');// Check for required environment variablescheckEnvVars('ABI_FILE_PATH','CONFIG_FILE_PATH','ETH_RPC_URL','BRIDGE_CONTRACT_ADDRESS');// Subscribe to an eventconstsubscribeToEvent=async(contract,eventConfig,ethNetwork,handleEvent)=>{if(!eventConfig.enabled)return;consteventName=eventConfig.name;constevent=contract.events[eventName]();event.on('data',async(eventData)=>{try{awaithandleEvent(eventName,eventData,contract._address,eventConfig);}catch(error){ethereumLogger.error(`Error ${eventName} event: ${error.message}`);}});event.on('error',(error)=>{ethereumLogger.error(`Web3 event error for ${eventName}: ${error}`);});event.on('connected',(id)=>{ethereumLogger.info(`${eventName} subscriptions (subscription id): ${id}`);});ethereumLogger.info(`${ethNetwork}:=> Listening for ${eventName} events of contract ${contract._address}`);};asyncfunctionlistenEthereumEvents(){constethWsUrl=process.env.ETH_RPC_URL;constcontractAddress=process.env.BRIDGE_CONTRACT_ADDRESS;// Initialize Web3letweb3;try{web3=awaitconnectWeb3(ethWsUrl);}catch(error){ethereumLogger.error(`Error connecting to Ethereum node: ${error.message}`);return;}// Load ABIletabi;try{abi=loadFile(process.env.ABI_FILE_PATH,'json');}catch(error){ethereumLogger.error(`Error loading ABI: ${error.message}`);return;}// Load configletconfig;try{config=loadFile(process.env.CONFIG_FILE_PATH,'yaml');}catch(error){ethereumLogger.error(`Error loading config: ${error.message}`);return;}// Get the network nameconstethNetwork=awaitethNetworkName(ethWsUrl);// Create contract instanceconstcontract=newweb3.eth.Contract(abi,contractAddress);// Get the current block numberconstblockNumber=awaitweb3.eth.getBlockNumber();ethereumLogger.info(`${ethNetwork}:=> Listening for events on block ${blockNumber}`);// Subscribe to eventsconsteventsConfig=config.eth.events;for(consteventConfigofeventsConfig){consteventName=eventConfig.name;if(eventConfig.enabled){ethereumLogger.info(`Subscribing to ${eventName} event`);try{awaitsubscribeToEvent(contract,eventConfig,ethNetwork,handleEthEvents);}catch(error){ethereumLogger.error(`Error subscribing to ${eventName} event: ${error.message}`);}}}// Subscribe to New block header to keep the connection alivetry{subscribeToEthNewBlockHeaders(web3,ethNetwork);}catch(error){console.error(`Error subscribing to new block headers: ${error.message}`);}}module.exports={ listenEthereumEvents };
To address this issue, here are some resources to explore:
Here is code that temporarily solves the issue by incorporating some of the suggestions found above, such as pinging, set provider, and reconnect listener.
asyncfunctionresetProviderAndResubscribe(web3,abi,config,ethNetwork,contractAddress){// Reset providerweb3.setProvider(newWeb3.providers.WebsocketProvider(process.env.ETH_RPC_URL));ethereumLogger.info(`ReConnected to ${ethNetwork} node:: ${process.env.ETH_RPC_URL}`);constblockNumber=awaitweb3.eth.getBlockNumber();// Initialize contractletcontractInstance;try{contractInstance=newweb3.eth.Contract(abi,contractAddress);}catch(error){ethereumLogger.error(`Error initializing contract: ${error}`);return;}// Avoid the Websocket connection to go idleawaitsubscribeToEthNewBlockHeaders(web3,ethNetwork);// Subscribe to eventsconsteventsConfig=config.eth.events;for(consteventConfigofeventsConfig){if(eventConfig.enabled){consteventName=eventConfig.name;ethereumLogger.info(`${ethNetwork}:=> ReSubscribing to ${eventName} event on block ${blockNumber}`);try{awaitsubscribeToContractEvents(contractInstance,eventConfig,ethNetwork,handleEthEvents);}catch(error){ethereumLogger.error(`Error subscribing to ${eventName} event: ${error}`);}}}}asyncfunctionlistenEthereumEvents(){constethWsUrl=process.env.ETH_RPC_URL;constcontractAddress=process.env.BRIDGE_CONTRACT_ADDRESS;constethNetwork=awaitethNetworkName(ethWsUrl);// Initialize Web3letweb3;try{web3=newWeb3(newWeb3.providers.WebsocketProvider(ethWsUrl),{},{delay: 500,autoReconnect: true,maxAttempts: 10,});ethereumLogger.info(`Connected to ${ethNetwork} node: ${ethWsUrl}`);}catch(error){ethereumLogger.error(`Error connecting to Ethereum node: ${error}`);return;}// Load ABIletabi;try{abi=loadFile(process.env.ABI_FILE_PATH,'json');}catch(error){ethereumLogger.error(`Error loading ABI: ${error}`);return;}// Load configletconfig;try{config=loadFile(process.env.CONFIG_FILE_PATH,'yaml');}catch(error){ethereumLogger.error(`Error loading config: ${error}`);return;}// Initialize contractletcontract;try{contract=newweb3.eth.Contract(abi,contractAddress);}catch(error){ethereumLogger.error(`Error initializing contract: ${error}`);return;}// Avoid the Websocket connection to go idleawaitsubscribeToEthNewBlockHeaders(web3,ethNetwork);letpingInterval;functionstartWebsocketPingInterval(){pingInterval=setInterval(async()=>{try{awaitweb3.eth.net.isListening();ethereumLogger.info(`${ethNetwork}:=> Websocket connection alive (ping successful)`);}catch(error){ethereumLogger.warn(`Ping failed, connection might be inactive, ${error}`);awaitresetProviderAndResubscribe(web3,abi,config,ethNetwork,contractAddress);}},5000);}startWebsocketPingInterval();// Get the current block numberconstblockNumber=awaitweb3.eth.getBlockNumber();// Subscribe to eventsconsteventsConfig=config.eth.events;for(consteventConfigofeventsConfig){if(eventConfig.enabled){consteventName=eventConfig.name;ethereumLogger.info(`${ethNetwork}:=> Subscribing to ${eventName} event on block ${blockNumber}`);try{awaitsubscribeToContractEvents(contract,eventConfig,ethNetwork,handleEthEvents);}catch(error){ethereumLogger.error(`Error subscribing to ${eventName} event: ${error}`);}}}web3.currentProvider.on('error',asyncerror=>{ethereumLogger.error(`Websocket Error: ${error}`);cleanup();startWebsocketPingInterval();});web3.currentProvider.on('end',asyncerror=>{ethereumLogger.error(`Websocket connection ended: ${error}`);cleanup();startWebsocketPingInterval();});process.stdin.resume();functioncleanup(){clearInterval(pingInterval);}process.on('exit',cleanup);process.on('SIGINT',cleanup);process.on('SIGUSR1',cleanup);process.on('SIGUSR2',cleanup);}module.exports={ listenEthereumEvents };
Logs
2024-04-11T23:49:58.404Z [ERROR]: Websocket Error: PendingRequestsOnReconnectingError: CONNECTION ERROR: Provider started to reconnect before the response got received!
2024-04-11T23:49:58.406Z [WARN]: Ping failed, connection might be inactive, PendingRequestsOnReconnectingError: CONNECTION ERROR: Provider started to reconnect before the response got received!
2024-04-11T23:49:58.415Z [INFO]: ReConnected to EnergyWebChain node:: wss://xxxxxxxx/ws
Environment
Network: Volta and EnergyWebChain
Node: v18.12.0 LTS or higher
NPM: v9.8.1
web3: "^4.4.0"
OS: Ubuntu 22.04 LTS
The text was updated successfully, but these errors were encountered:
Hi @royki , thanks for publishing this here!
FYI @jdevcs@avkos@Muhammad-Altabba@luu-alex we tried different code samples (the ones that are in the docs as well) and it didn't work, its not reconnecting
I got the same issue. I try print the error log ErrorEvent {Symbol(kTarget): WebSocket, Symbol(kType): 'error', Symbol(kError): RangeError: Invalid WebSocket frame: inval…06 at Receiver.controlMessage (/User…, Symbol(kMessage): 'Invalid WebSocket frame: invalid status code 1006'}
Expected behavior
The WebSocket connection to the Ethereum node should remain active. The connection should continuously listen to smart contract events.
Actual behavior
The WebSocket connection to the Ethereum node either closes or becomes idle after some time (approximately 5-6 hours or 10 hours). When this happens, the reconnection attempts fail to listen to smart contract events.
Steps to reproduce the behavior
Subscribe to new block headers and smart contract events.
subscribeToEthNewBlockHeaders
.To address this issue, here are some resources to explore:
Here is code that temporarily solves the issue by incorporating some of the suggestions found above, such as pinging, set provider, and reconnect listener.
Logs
Environment
Volta
andEnergyWebChain
v18.12.0 LTS
or higherv9.8.1
"^4.4.0"
Ubuntu 22.04 LTS
The text was updated successfully, but these errors were encountered: