Futures combinators: How to do error handling?


#1

Hi.

I’ve managed to get the following code compiling:

pub fn post_register(register_data: Json<Register>, state: State<api::State>) -> FutureResponse<HttpResponse> {
    tokio_timer::sleep(Duration::from_millis(400)).into_future()
    .map_err(|_| api::Error::Internal)
    // .map_err(|_| actix::prelude::MailboxError::Timeout)
    // .from_err()
    // .map(|x| futures::future::ok(x))
    // .flatten()
    .and_then(move |_|
        state
        .db
        .send(GetAllPendingAccounts).flatten()
    )
    .map_err(|_| api::Error::Internal)
    // .from_err()
    // .flatten()
    .and_then(move |res| {
        let res = api::Response::data(res);
        Ok(HttpResponse::Ok().json(&res))
    })
    .map_err(|_| api::Error::Internal)
    .from_err()
    .responder()
    // Ok(HttpResponse::Ok().json(&res))
    // Ok(api::Response::data(register_data.0))
}

But I’m not sure what is happening step by step.

What I’m trying to do is:

  • wait for 400ms without blocking reactor, if an error happens returns an api::Error::Internal
  • then send a GetAllPendingAccounts to my db Actor
  • then send the data
  • if any of these steps fails, send api::Error::Internal.

What I’m not sure to understand is:

  • if one of the futures fails, when does the chain break ?
  • Why I need to append flatten after .send(GetAllPendingAccounts) to get it working (otherwise I have Error conversion errors) ?
  • why I need to add .map_err(|_| api::Error::Internal) after each and_then step ?
  • in a chain of futures, all ‘steps’ must returns the same error type right ?
  • What is the best way to and_then a future without flaten ?

#2

I can at least answer one of your questions:

This is because send() returns a Future so the outer call of and_then() would return a Future that resolves to a Future. The flatten() method ‘flattens’ the Future-Future to a simple Future resolving to <state.db as Handler<GetAllPendingAccounts>::Result.


#3

Thanks!
It’s very different from JS where each of your then blocks returns a future.

Is there a way (special combinator?) to avoid this flatten call when our and_then call return a future ?