Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a timeout for WebSocket connections #1889

Open
timas130 opened this issue Nov 23, 2022 · 4 comments
Open

Add a timeout for WebSocket connections #1889

timas130 opened this issue Nov 23, 2022 · 4 comments

Comments

@timas130
Copy link

timas130 commented Nov 23, 2022

Is your feature request related to a problem? Please describe.
Some RPC services (like QuickNode) completely drop WebSocket requests that go above the speed limit. They don't even respond with anything or terminate the connection - the request gets ignored. And when that happens, the library just waits for the response endlessly.

Describe the solution you'd like
An option to set the timeout for Ws.

Describe alternatives you've considered
Just wrapping the Future in a function like this:

async fn with_timeout<T: Future>(future: T) -> T::Output {
    tokio::select! {
        result = future => result,
        _ = tokio::time::sleep(std::time::Duration::from_secs(3)) => {
            panic!("timeout reached");
        }
    }
}

This doesn't work with subscriptions, though.

@0xMelkor
Copy link
Contributor

0xMelkor commented Nov 23, 2022

Hello,
In the past I had the same problem with Quicknode. I found out this working pattern

    // This loop iterates upon inactivity timeouts.
    'connection: loop {

        let client = Provider::<Ws>::connect("wss://your-uri").await?;
        let client = Arc::new(client);
        let filter = Filter::new().event("Transfer(address,address,uint256)");

        let mut stream = client.subscribe_logs(&filter).await?;

       // We loop over stream.next(). If a timeout occurs we break the loop and connect again
       'listen: loop {
           let timeout = time::sleep(Duration::from_secs(30));
           tokio::pin!(timeout); // You need to pin the timeout future to use in tokio::select!

           tokio::select! {
               filter = stream.next() => {
                 // Do some work
               }
               _ = &mut timeout => {
                   // Timeout reached
                   break 'listen;
               }
           }
       }
   }

If you are interested there is a previous PR left open to cope with WS reconnection at the transport layer
1675

@timas130
Copy link
Author

@0xMelkor Thanks for the advice. That's basically what I'm using, just a bit more prettily written. :) Feel free to close the issue if you're not going to fix this.

@0xMelkor
Copy link
Contributor

@timas130 I'm afraid I have not permissions to close this.
Can you share how you would rewrite this snippet? That's useful to me and maybe someone else in the future.
Thanks.

@timas130
Copy link
Author

timas130 commented Nov 24, 2022

@0xMelkor I mean that your snippet is easier to understand. The code I'm using is shown in the issue description.

Anyways, I think that even though it is possible to wrap the function like that, it should probably be included as a standard feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants