async-book icon indicating copy to clipboard operation
async-book copied to clipboard

Timeout question

Open vjancik opened this issue 5 years ago • 0 comments

Hi! First of all, thank you for a great resource!

Then, I made a timeout future, extending on the TimerFuture and Executor from the current sections of the book.

pub enum Result<T> { Completed(T), TimedOut }

pub async fn timeout<T>(future: impl Future<Output=T> + Unpin, timeout: Duration) -> Result<T> {
    let (abort_handle, abort_registration) = AbortHandle::new_pair();
    let abortable_future = Abortable::new(future, abort_registration);
    let mut fused_future = abortable_future.fuse();

    let fused_timer = TimerFuture::new(timeout).fuse();
    pin_mut!(fused_timer);

    // could cause a race if timer and future end at the same time?
    let result: Result<T> = select! {
        res_1 = fused_future => Result::Completed(res_1.unwrap()),
        _ = fused_timer => Result::TimedOut,
    };

    if let Result::TimedOut = result {
        abort_handle.abort();
    }

    result
}

I apologize for any glaring redundancies, I'm new to Rust.

My question is, before I used an async function for the timeout implementation I tried to make a TimeoutFuture implementation similar to the TimerFuture from scratch, and ran into the issue of not being able to pass through / spawn the passed in timed future from inside the TimeoutFuture implementation. Is there any canonical way to get around this? For a Future implementation to spawn another Future?

Also, secondly, my AbortHandle doesn't seem to work, I assume this is because it requires some support from the Executor::run function?

Hope to see some new chapters!

PS: The HTTP server has a nice cleaner version with hyper 1.30.0 without the need for compat.

use std::convert::Infallible;
use std::net::SocketAddr;
use hyper::{Body, Request, Response, Server, 
            service::{make_service_fn, service_fn}};

async fn req_handler(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new(Body::from("hello, world!.")))
}

async fn run_server(addr: SocketAddr) {
    println!("listening on http://{}", addr);

    let service = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(req_handler))
    });

    let server = Server::bind(&addr).serve(service);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }
}

// as per hyper 1.30.0 release notes recommendation
#[tokio::main]
async fn main() {
    let addr = SocketAddr::from(([127, 0, 0, 1], 7878));

    run_server(addr).await;
}

vjancik avatar Dec 13 '19 21:12 vjancik