Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example for Reconnect #566

Closed
fredrik-jansson-se opened this issue Feb 23, 2021 · 4 comments
Closed

Example for Reconnect #566

fredrik-jansson-se opened this issue Feb 23, 2021 · 4 comments

Comments

@fredrik-jansson-se
Copy link

Hi!

I've tried to use Reconnect on top of a tonic (gRPC) client, but I really cannot figure out how to do it. :(

Would you consider adding an example on how to use Reconnect, could be as simple as reconnecting a TCPStream?

@fredrik-jansson-se
Copy link
Author

Or if someone would be willing to give me some hints, I'd be more than happy to create a PR for an example :)

@davidpdrsn
Copy link
Member

Does this help:

use std::{
    pin::Pin,
    task::{Context, Poll},
    time::Duration,
};
use tower::{reconnect::Reconnect, service_fn, BoxError, Service, ServiceExt};

#[tokio::main]
async fn main() {
    let svc = MyService::default();

    let make_service = service_fn(|_target: ()| {
        // the future produced by the service must be `Unpin`
        Box::pin(async {
            println!("reconnecting");
            tokio::time::sleep(Duration::from_secs(2)).await;
            Ok::<_, BoxError>(svc)
        })
    });

    let mut svc = Reconnect::new::<MyService, String>(make_service, ());

    loop {
        let response = svc.ready().await.unwrap().call(()).await.unwrap();
        dbg!(&response);
    }
}

#[derive(Debug, Copy, Clone, Default)]
struct MyService {
    counter: usize,
}

impl Service<()> for MyService {
    type Response = String;
    type Error = BoxError;
    type Future = Pin<
        Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>,
    >;

    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        if self.counter < 10 {
            self.counter += 1;
            Poll::Ready(Ok(()))
        } else {
            // `MyService` dies after 10 requests
            Poll::Ready(Err(BoxError::from("dead".to_string())))
        }
    }

    fn call(&mut self, _request: ()) -> Self::Future {
        let count = self.counter;
        Box::pin(async move { Ok(format!("request {}", count)) })
    }
}

MyService is a service that "dies" after 10 requests. But using Reconnect and make_service it transparently creates new services. Similarly to re-establishing network connections. For example hyper's HttpConnector is a Service<Uri> that yields TcpStreams.

@fredrik-jansson-se
Copy link
Author

Hey David,

sorry for being slow on responding, been AFK.

Thank you!

I'll take a look at this asap.

@davidpdrsn
Copy link
Member

@fredrik-jansson-se I'll close this for now. Feel free to re-open if you have more questions :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants