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

How to use several services using the Tower service approach #309

Closed
robertohuertasm opened this issue Mar 29, 2020 · 8 comments
Closed

Comments

@robertohuertasm
Copy link

robertohuertasm commented Mar 29, 2020

I was using add_service to do multiplexing of several services but I needed to implement some sort of middleware in order to validate a token. I went first with the interceptor approach but didn't work for me as they don't seem to support async and I need to occasionally make a request to a third party server to make a validation.

Then I went for the warp/tonic/tower example in order to get access to the request and do some async stuff before calling the service. But then, a couple of questions arose:

Server::bind(&addr)
    .serve(make_service_fn(move |_| {
        let mut server = server.clone();
        async {
            let tw_svc = tower::service_fn(move |req: hyper::Request<hyper::Body>| {
                server.call(req)
            });
            Ok::<_, Infallible>(tw_svc)
        }
    }))
    .await?;
  1. How could I use several services as when I was using add_service in such scenario? i.e. if I needed to add server2 how would I proceed?
  2. I'm having issues using async inside the closure passed as argument to tower::service_fn. If I use it I get compiler errors when I await the result of the call (async { server.call(req).await } => captured variable cannot escape FnMut closure body). I can overcome this issue by not using async/await and using just futures chain methods (e.g. and_then), so it's not a blocker for the moment. Just curious about whether there are other ways to solve this.
  3. Is there a recommended way to deal with async middlewares other than this approach?

I suspect this question is not really related to Tonic but to how it relates to Hyper and Tower. I'm starting to get dirty with all these libs so apologies if the question is naive. 😉

@LucioFranco
Copy link
Member

@robertohuertasm do you need to make a request for the token on each request or can you have some sort of background task that say updates a mutex? If you can go with the later version (which I have seen is more) common you can use the interceptors.

Otherwise, we have an issue #269 for exposing a way to instead of serving directly from the router to expose its generated service that you can then call directly in your own hyper implementation.

@robertohuertasm
Copy link
Author

@LucioFranco this token is the one authorizing the caller to access to the grpc api so it has to be validated prior to accessing the resource. The authorization server is third party server, so I have to make a request there. I guess I could add this logic to each endpoint in the services but I was wondering if there was a simple way to add a middleware wrapping all these calls.

So, according to your answer, should I assume that by using the Tower service approach, for the moment, I should manage the routing to the different services myself? Is that right? At least until #269 story gets merged.

@LucioFranco
Copy link
Member

I think here then adding it to each handler in the async fn actually might be easier to understand and reason about than writing some complex service stack?

In theory you could just add a validate_token(&req).await? to each call. I think that would be prefered here.

If you want to go with the tower method then you will have to do the routing by yourself for now. You can peek in the transport module to see how I handle some of that but it is quite complex.

@robertohuertasm
Copy link
Author

Yes, I took a look at it yesterday to understand how the Router was working. Thanks @LucioFranco for your help and your awesome work! 👍 I think I have enough options for the moment to cover my use case.

@LucioFranco
Copy link
Member

@robertohuertasm great, feel free to hop on the discord and ping me if you have any further questions!

@robertohuertasm
Copy link
Author

btw, which discord channel are you in? I was looking for it but couldn't find it. Is it the Rustlang discord or a specific one?

@LucioFranco
Copy link
Member

LucioFranco commented Mar 30, 2020

@robertohuertasm we have a tokio based one here https://discord.gg/tokio and there is a #tonic channel

@robertohuertasm
Copy link
Author

That's awesome! Thanks again @LucioFranco!

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