ethers.js icon indicating copy to clipboard operation
ethers.js copied to clipboard

Event Listeners Stop Firing

Open JimLynchCodes opened this issue 3 years ago • 21 comments

Note: Not all sections may be relevant, but please be as thorough while remaining concise as possible. Remove this Notice and any sections that don't feel pertinent.

If you are unsure if something is a bug, start a thread in the "discussions" tab above..

Describe the bug

I am using the ".on" syntax to listen for an event that my contract emits. Something like this:

myContract.on('MyEvent', async (someParam) => {

  console.log('heard MyEvent!')
})

Reproduction steps

  • Run a node.js process with this listener waiting for the event to be emitted.
  • See that when the contract emits the event, the node process callback is fired
  • wait a few hours
  • See that when the contract emits the event, the node process callback is NOT fired...

Environment: Please include anything that may be useful in diagnosing the issue. Node vs Browser? Geth vs Parity vs Ganache? Third Party tools, like Hardhat? Mobile vs. Desktop? all environments

Search Terms Often similar issues have come up before. Include any search terms you have tried in this repository's Issues (including closed issues) and "Discussions", so if there are matching issues, we can be sure to add those keywords and link this issue to it, making it easier for people to find in the future.

JimLynchCodes avatar Nov 27 '21 22:11 JimLynchCodes

do I need to manually re-establish a connection to something? I tried setting up the provider like this, but my "end" and "error" callbacks never seem to be fired...

let provider = new ethers.providers.WebSocketProvider(connectionUrl)
console.log('provider created.')

provider.on('end', (e) => {
  console.log('provider ended: ' + e);
  provider = new ethers.providers.WebSocketProvider(connectionUrl)
})

provider.on('error', (e) => {
  console.log('provider errored: ' + e);
  provider = new ethers.providers.WebSocketProvider(connectionUrl)
})

JimLynchCodes avatar Nov 27 '21 22:11 JimLynchCodes

Which provider are you using?

ricmoo avatar Nov 27 '21 22:11 ricmoo

You may need to use keep-alive pings to keep the provider alive (e.g. by calling something like getBlockNumber periodically). The WebSocket provider does not reconnect and re-subscribe to events in v5, since the v5 WebSocket provider wasn’t intended for long-term connections with no data transfer. Keep in mind, in this case this can consume significant server resources.

I’m working on the v6 Subscription model now so that it can reconnect for you, and take care of exactly-once semantics for resubscribing, and also has a pause and resume feature.

ricmoo avatar Nov 27 '21 22:11 ricmoo

Note: Not all sections may be relevant, but please be as thorough while remaining concise as possible. Remove this Notice and any sections that don't feel pertinent.

If you are unsure if something is a bug, start a thread in the "discussions" tab above..

Describe the bug

I am using the ".on" syntax to listen for an event that my contract emits. Something like this:

myContract.on('MyEvent', async (someParam) => {

  console.log('heard MyEvent!')
})

Reproduction steps

  • Run a node.js process with this listener waiting for the event to be emitted.
  • See that when the contract emits the event, the node process callback is fired
  • wait a few hours
  • See that when the contract emits the event, the node process callback is NOT fired...

Environment: Please include anything that may be useful in diagnosing the issue. Node vs Browser? Geth vs Parity vs Ganache? Third Party tools, like Hardhat? Mobile vs. Desktop? all environments

Search Terms Often similar issues have come up before. Include any search terms you have tried in this repository's Issues (including closed issues) and "Discussions", so if there are matching issues, we can be sure to add those keywords and link this issue to it, making it easier for people to find in the future.

I have the same problem. Did you find a good solution? https://github.com/tarik0/ReconnectableEthers

ndfnd avatar Dec 04 '21 09:12 ndfnd

@ndfnd I did NOT find a good solution...

@ricmoo I tried that- still doesn't work. I am pinging for the block number every 15 min.

I am creating the provider like this:

let provider = new ethers.providers.WebSocketProvider(
  new Web3WsProvider(connectionUrl, options))

The pings all go through fine- every after the .on events stop firing, the pings still work (so pinging the server does not seem to help AT ALL).

I am very disappointed... everything ethereum-related seems to be super jank. 😢

JimLynchCodes avatar Dec 17 '21 15:12 JimLynchCodes

I guess there is no solution?

Listeners will always break after a short time?

JimLynchCodes avatar Feb 22 '22 15:02 JimLynchCodes

Are you facing this problem with WebSocketProvider specifically? Can you check if the same code with JsonRpcProvider works fine?

zemse avatar Feb 23 '22 19:02 zemse

Are you facing this problem with WebSocketProvider specifically? Can you check if the same code with JsonRpcProvider works fine?

problem happened on jsonrpcprovider and alchemyprovider as well

aindong avatar Apr 12 '22 09:04 aindong

The pings all go through fine- every after the .on events stop firing, the pings still work (so pinging the server does not seem to help AT ALL).

I have the exactly same problem. Looks like I have to re-listen to the events manually periodically.

edit: also see #2969 #1053

songkeys avatar Jun 11 '22 14:06 songkeys

to re-listen to the events manually periodically.

How do you relisten to events periodically?

hedgehog-millenium avatar Jun 06 '23 18:06 hedgehog-millenium

I’m working on the reconnect and resubscribe logic. It has to handle the async nature and populate the intermediate events using getLogs. I have a plan. I just need time to implement it. :)

ricmoo avatar Jun 06 '23 18:06 ricmoo

(Keep in mind polling subscribers currently do not have this problem, so you can explicitly enable them and this won’t be a problem for you. The filter ID backed subscribers need additional logic though, which is next on my backlog)

ricmoo avatar Jun 06 '23 18:06 ricmoo

(Keep in mind polling subscribers currently do not have this problem, so you can explicitly enable them and this won’t be a problem for you. The filter ID backed subscribers need additional logic though, which is next on my backlog)

Then with JsonRpcProvider polling new errors arise (like @TODO result is not iterable )

hedgehog-millenium avatar Jun 06 '23 18:06 hedgehog-millenium

@hedgehog-millenium What backend are you using? I believe that indicates the backend is returning null instead of a result. I’ll be fixing that too, whereby the result is dropped, but an error event is emitted.

But that likely means the backend is misbehaving, so your results may already suffer.

There are several minor-bump issues you can check out which include these changes, I think.

One more quick question is which network are you using? I added a fix for polygon/bnb in v6.4.2 yesterday for these types of networks when polling.

ricmoo avatar Jun 06 '23 18:06 ricmoo

@hedgehog-millenium What backend are you using? I believe that indicates the backend is returning null instead of a result. I’ll be fixing that too, whereby the result is dropped, but an error event is emitted.

But that likely means the backend is misbehaving, so your results may already suffer.

There are several minor-bump issues you can check out which include these changes, I think.

One more quick question is which network are you using? I added a fix for polygon/bnb in v6.4.2 yesterday for these types of networks when polling.

Thank you for quick reply @ricmoo . The back end i'm using is a hardhat local network which is running in docker container. I did a lot of experiments with WbSocketProvider as well as JsonRpcProvider . I start to receive events with no issue , handle then and write to DB . But after arrond 3-5 minutes the issue happens and it seems to happen event when you continue triggering new events (like it there is an hardcoded interval). I tried to put ping-pong logic to setInterval to keep the connection alive , also istead of ping-pong tried to request blockNumber in setInterval . In all scenarios I see responses from provider but once it comes to events with jsonRpcProvider after 3-5 minutes there is @TODO TypeError: results is not at FilterIdEventSubscriber._emitResults with WebSocetProvider events are just not being caught

hedgehog-millenium avatar Jun 07 '23 07:06 hedgehog-millenium

@JimLynchCodes @hedgehog-millenium I'm also facing this issue currently. Did you get any solution for this?

rajat-unifarm avatar Sep 11 '23 07:09 rajat-unifarm

In our project we've fixed it by forcing the hardhat node generating new blocks, i.e.


 const config: HardhatUserConfig = {
     solidity: '0.8.20',
     networks: {
         hardhat: {
             // See: https://hardhat.org/hardhat-network/docs/reference#mining-modes
             mining: {
                 auto: true,
                 // Produce new block every 3 minutes to resolve next issues
                 // https://github.com/NomicFoundation/hardhat/issues/2053
                 // https://github.com/ethers-io/ethers.js/issues/2338
                 // https://github.com/ethers-io/ethers.js/discussions/4116
                 interval: 3 * 60 * 1000, // should be less then 5 minutes to make event subscription work
             },
         },
     },
 };

This is important since the 5 minute deadline is getting expired due to the fact that it's not renewed when reading the filter changes which happens in ethers only once a new block is generated.

sertony avatar Feb 14 '24 07:02 sertony