I'm trying to implement routine that keeps trying different hosts from a list until one of them responds using futures. ConnectError
here just means "retry". What I came up with is the following code (simplified). Is there any better way to achieve this? Using skip_while
doesn't seem to help because it produces bool and I need the Response
for later use.
struct Response { ok: bool }
#[derive(Debug)]
struct ConnectError {}
#[derive(Debug)]
struct ResponseError {}
fn post(port: u16, try: usize)
-> impl Future<Item=Response, Error=ConnectError> {
println!("posting to {}, take #{}", port, try);
if port == 8765 && try == 3 {
futures::future::ok( Response { ok: true } )
} else {
futures::future::err( ConnectError {} )
}
}
fn process_response(resp: Response)
-> impl Future<Item=(), Error=ResponseError> {
if resp.ok {
futures::future::ok( () )
} else {
futures::future::err( ResponseError {} )
}
}
fn main() {
let tuples = (1..10).flat_map(
|i| [8764, 8765, 8766].iter().map(move |p| (i, *p))
);
let round_robin = futures::stream::iter_ok::<_, ConnectError>(tuples)
.and_then(|(i, p)| post(p, i))
.inspect_err(|conn_err| println!("{:?}", conn_err))
.take(1)
.then(|result| futures::future::ok(result))
.filter_map(|result| result.ok())
.and_then(|response| process_response(response)
.map_err(|resp_err| println!("{:?}", resp_err))
)
.fold((), |(), ()| futures::future::ok(()));
tokio::run(round_robin);
}