smol icon indicating copy to clipboard operation
smol copied to clipboard

smol::spawn: BrokenPipe io::copy failed

Open bbros-dev opened this issue 3 years ago • 0 comments

We observe a stream of these errors:

Connection error: Custom {
    kind: BrokenPipe,
    error: VerboseError {
        source: Os {
            code: 32,
            kind: BrokenPipe,
            message: "Broken pipe",        },
        message: "io::copy failed",
    },
}

when running rewrk --json -t 12 -c 500 -d 30s -h http://127.0.0.1:3000 against this simplified version of the examples/async-h1-server (with tls removed):

use std::net::TcpListener;

use anyhow::Result;
use http_types::{Request, Response, StatusCode};
use smol::Async;

/// Serves a request and returns a response.
async fn serve(_req: Request) -> http_types::Result<Response> {
    let mut res = Response::new(StatusCode::Ok);
    res.insert_header("Content-Type", "text/plain");
    res.set_body("Hello, World!");
    Ok(res)
}

/// Listens for incoming connections and serves them.
async fn listen(listener: Async<TcpListener>) -> Result<()> {
    loop {
        // Accept the next connection.
        let (stream, _) = listener.accept().await?;

        // Spawn a background task serving this connection.
        let stream = async_dup::Arc::new(stream);
        let task = smol::spawn(async move {
            if let Err(err) = async_h1::accept(stream, serve).await {
                println!("Connection error: {:#?}", err);
            }
        });

        // Detach the task to let it run in the background.
        task.detach();
    }
}

fn main() -> Result<()> {
    // Start HTTP server.
    smol::block_on(async {
        let http = listen(Async::<TcpListener>::bind(([127, 0, 0, 1], 3000))?);
        http.await?;
        Ok(())
    })
}

There are no build errors. We have found that if instead we use a smol::Executor these errors go away. Specifically, replace:

let task = smol::spawn(async move {
            if let Err(err) = async_h1::accept(stream, serve).await {
                println!("Connection error: {:#?}", err);
            }
        });

        // Detach the task to let it run in the background.
        task.detach();

with:

let ex = smol::Executor::new();
        ex.spawn(async move {
            if let Err(err) = async_h1::accept(stream, serve).await {
                println!("Connection error: {:#?}", err);
            }
        })
        .detach();

We aren't sure if:

  • the example should just be updated,
  • we have used smol::spawn incorrectly
  • there is an issue with smol::spawn

bbros-dev avatar Mar 11 '22 06:03 bbros-dev