Tokio: WouldBlock error with udp socket

Created on 7 May 2020  ยท  8Comments  ยท  Source: tokio-rs/tokio

Version

โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ tokio v0.2.20
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ tokio-macros v0.2.5
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ tokio-util v0.3.1
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ tokio v0.2.20 (*)
โ”‚   โ”‚   โ”œโ”€โ”€ tokio v0.2.20 (*)
โ”‚   โ”‚   โ”œโ”€โ”€ tokio v0.2.20 (*)
โ”‚   โ”‚   โ”œโ”€โ”€ tokio-rustls v0.13.0
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ tokio v0.2.20 (*)
โ”‚   โ”œโ”€โ”€ tokio v0.2.20 (*)
โ”‚   โ”œโ”€โ”€ tokio-rustls v0.13.0 (*)
โ”œโ”€โ”€ tokio v0.2.20 (*)

Platform

Linux hostname 5.4.39 #1-NixOS SMP Wed May 6 06:15:17 UTC 2020 x86_64 GNU/Linux

Description

I use the serenity crate to build a discord bot. That crate isn't async but I would like to use async code with it.

The code "works" on my computer at home but not on my tiny vps at digital ocean. I wonder if it's because it only has 1 CPU.

The wouldblock error seems to happen while I'm reading the socket (with a send_to before).

    let mut buf = vec![0; 1024];
    let (n, _peer) = socket.recv_from(&mut buf).await?;

One weird thing is that last night I had the 'wouldblock' error but this morning it just hangs.

I can't reproduce with simpler code right now but it's something like:

fn main() -> Result<(), Error> {
    use tokio::runtime::Runtime;
    let mut rt = Runtime::new().unwrap();

    let handle = rt.handle().clone();

    // also tried tokio::task::spawn_blocking
    thread::spawn(move || {
        start_serenity(handle).unwrap();
    });

    use futures::future;

    let f = future::pending::<()>();
    rt.block_on(f);
}

// some serenity command
#[command]
fn something(ctx: &mut Context, msg: &Message) -> CommandResult {
    // get the handle from ctx

    let (tx, rx) = unbounded();

    handle.spawn(async move {
        // here I use a tokio::net::UdpSocket
        // send result using tx channel
    });

    let result = rx.await;
}
A-tokio C-bug E-needs-mcve M-net

Most helpful comment

I'll try that today.

Btw I also have the problem with async-std 1.6.0-beta.1 which uses the new smol runtime. Which isn't based on mio I think.

All 8 comments

That sounds weird. It shouldn't return WouldBlock. I need more details, though.

I'm going to try to reproduce.

Meanwhile. my vps rebooted (and did an OS update) last night. I wonder if that changed anything.

Also the wouldblock error messages had "Resource temporarily unavailable (os error 11)". I have no idea if it's always the case or not.

Are you still having issues with this?

Yes.

If I swap tokio for async-std and it hangs I still have the "WouldBlock" error. Does that mean that the problem has nothing to do with tokio?

My program is still running stuff using tokio. I use serenity which uses reqwest which uses tokio.

I mean Tokio and async-std share the same IO backend mio, so it might be an issue on that level. If you are able to create a small test case that shows the error, that would be amazing.

Alternatively, a way to help out would be to add some prints in poll_recv_from to check which question mark returned the error.

#[doc(hidden)]
pub fn poll_recv_from(
    &self,
    cx: &mut Context<'_>,
    buf: &mut [u8],
) -> Poll<Result<(usize, SocketAddr), io::Error>> {
    match self.io.poll_read_ready(cx, mio::Ready::readable()) {
        Poll::Ready(Ok(())) => {},
        Poll::Ready(Err(e)) => {
            if e.kind() == io::ErrorKind::WouldBlock {
                println!("WouldBlock from poll_read_ready");
            }
            return Poll::Ready(Err(e))
        },
        Poll::Pending => return Poll::Pending,
    }

    match self.io.get_ref().recv_from(buf) {
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
            if let Err(e) = self.io.clear_read_ready(cx, mio::Ready::readable()) {
                if e.kind() == io::ErrorKind::WouldBlock {
                    println!("WouldBlock from clear_read_ready");
                }
                Poll::Ready(Err(e))
            } else {
                Poll::Pending
            }
        }
        x => Poll::Ready(x),
    }
}

You can use an alternate version of Tokio with a patch section.

[dependencies]
tokio = { version = "0.2.21", features = ["full"] }

[patch.crates-io]
tokio = { path = '/path/to/modified/tokio' }

I'll try that today.

Btw I also have the problem with async-std 1.6.0-beta.1 which uses the new smol runtime. Which isn't based on mio I think.

I'm still trying to find which commit I had that was using tokio::net::UdpSocket and had the WouldBlock error.

The code I'm testing right now just blocks forever (on my tiny vps but is fine on my desktop). Can I do something to debug that?

If I had a firewall issue, would I get an WouldBlock message and I would have to use tokio::time::timeout?

EDIT: It seems to be a firewall or wireguard issue. I forgot that my vps has a vpn with the other host.

Was this page helpful?
0 / 5 - 0 ratings