web3js – Solving WebSocket Connection Issues with Infura and Web3.js

infuraweb3js

I know this question have been asked several times and many solutions are being proposed as a workaround but not sure why it is not been working on our case.

In our case we have to listen for contract events like Transfer events on our backend (node js) so that we can update our investor balances and perform other sensitive activities. We can't afford to lose events in our case.

For this, we are using WebSocket provider from infura and web3js library to connect with them. We noticed that if for a few hours we are'nt make any calls then it would close that connection and we would have to restart our app for new connections.
To work around this issue we applied popular community workaround i.e listen for events like end or error on the provider and if those events occur we would make a call to instantiate a connection but after applying this patch web3 throws below error instead of connection not open error

'Connection dropped by remote peer.

Here is simplified code of our blockchain module.

const web3  = require('web3');
const ethtx = require('ethereumjs-tx');
const path = require('path');
const fs = require('fs');
const Tx = require('ethereumjs-tx');

const updatebalancedb  = require('../db/Admins/Transactions/updatebalance.js');
const dotenv = require('dotenv');
dotenv.config();



var masterwalletpublickey = process.env.daopublicaddress;
var masterwalletprivatekey = Buffer.from(process.env.daoprivatekey, 'hex');
var wsscocketprovider = process.env.infuranode;
var parentcontractaddress = process.env.maincontractaddress;

var provider = new web3.providers.WebsocketProvider(wsscocketprovider);

var web3js = new web3(provider);

provider.on('error', e => 
{
console.log('WS Error', e);
provider = new web3.providers.WebsocketProvider(wsscocketprovider);
});
provider.on('end', e => {
    console.log('WS closed');
    console.log('Attempting to reconnect...');
    provider = new web3.providers.WebsocketProvider(wsscocketprovider);

    provider.on('connect', function () {
        console.log('WSS Reconnected');
    });

    web3js.setProvider(provider);
});





 const rawcontract  = JSON.parse(fs.readFileSync(path.join(__dirname,'../BlockchainModule/build/contracts/ErContract.json')));
 const contractabi = JSON.stringify(rawcontract.abi);

const contract = new web3js.eth.Contract(rawcontract.abi,parentcontractaddress);


contract.events.Transfer()
.on('data', (event) => {
    console.log('data',event);
    var data = event;
    updatebalancedb.updateinvestorbalance(data);
})
.on('error', console.error);


const gettotaltokens = function(){


    return   contract.methods.totaltokens().call()
        .then(function(result){
            return result;

        })
        .catch(function(error){
           throw error; 
        }) 

}


const circulationtokens = function(){

    return contract.methods.circulationsupply().call()
        .then(function(result){
            return result;
        })
        .catch(function(error){
            throw error;
        })
};

module.exports={gettotaltokens,circulationtokens};

When we call functions like gettotaltokens after few hours of connectivity web3 throws such error .

Can anyone give some pointers or some guide of how to solve this messy issue?

The only solution I have in my mind is to move web3 provider code to a functional level and every time we call the function it will start a fresh new connection. That will solve the problem for time being but not very scalable and also wouldn't solve event listener issues.

Tech Environment:

  1. Node js (v10.13.0)
  2. web3.js (1.2.3)
  3. Chain : (Ropsten)
  4. Socket Provider (Infura)

Best Answer

I hope someone from Infura would comment the specifics when they terminate a connection.

However, the latest Web3.js has autoreconnect feature:

https://github.com/ethereum/web3.js/releases/tag/v1.2.7

It should alleviate your problems.