use futures::{Future, Poll};
use client::ClientHandle;
use error::*;
use op::Message;
#[derive(Clone)]
#[must_use = "queries can only be sent through a ClientHandle"]
pub struct RetryClientHandle<H: ClientHandle> {
client: H,
attempts: usize,
}
impl<H> RetryClientHandle<H>
where H: ClientHandle
{
pub fn new(client: H, attempts: usize) -> RetryClientHandle<H> {
RetryClientHandle {
client: client,
attempts: attempts,
}
}
}
impl<H> ClientHandle for RetryClientHandle<H>
where H: ClientHandle + 'static
{
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ClientError>> {
let future = self.client.send(message.clone());
return Box::new(RetrySendFuture {
message: message,
client: self.client.clone(),
future: future,
remaining_attempts: self.attempts,
});
}
}
struct RetrySendFuture<H: ClientHandle> {
message: Message,
client: H,
future: Box<Future<Item = Message, Error = ClientError>>,
remaining_attempts: usize,
}
impl<H> Future for RetrySendFuture<H>
where H: ClientHandle
{
type Item = Message;
type Error = ClientError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
match self.future.poll() {
r @ Ok(_) => return r,
Err(e) => {
if self.remaining_attempts == 0 {
return Err(e);
}
self.remaining_attempts = self.remaining_attempts - 1;
self.future = self.client.send(self.message.clone());
}
}
}
}
}
#[cfg(test)]
mod test {
use std::cell::Cell;
use client::*;
use error::*;
use op::*;
use futures::*;
#[derive(Clone)]
struct TestClient {
last_succeed: bool,
retries: u16,
attempts: Cell<u16>,
}
impl ClientHandle for TestClient {
fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = ClientError>> {
let i = self.attempts.get();
if i > self.retries || self.retries - i == 0 {
if self.last_succeed {
let mut message = Message::new();
message.set_id(i);
return Box::new(finished(message));
}
}
self.attempts.set(i + 1);
return Box::new(failed(ClientErrorKind::Message("last retry set to fail").into()));
}
}
#[test]
fn test_retry() {
let mut client = RetryClientHandle::new(TestClient {
last_succeed: true,
retries: 1,
attempts: Cell::new(0),
},
2);
let test1 = Message::new();
let result = client.send(test1)
.wait()
.ok()
.expect("should have succeeded");
assert_eq!(result.id(), 1); }
#[test]
fn test_error() {
let mut client = RetryClientHandle::new(TestClient {
last_succeed: false,
retries: 1,
attempts: Cell::new(0),
},
2);
let test1 = Message::new();
assert!(client.send(test1).wait().is_err());
}
}