diff --git a/docs/learning_grpc.md b/docs/learning_grpc.md index 8a8d451..154fe22 100644 --- a/docs/learning_grpc.md +++ b/docs/learning_grpc.md @@ -350,17 +350,18 @@ Mechanism to layer services. It allows us to wrap a generic service with another ```rust ServiceBuilder::new() - .timeout(Duration::from_secs(10)) - .layer(OpenTelemetryServerTracingLayer::new_for_grpc()) + .layer(TimeoutLayer::new(Duration::from_secs(10))) + .layer(OpenTelemetryTracingLayer::new()) .layer(JwtAuthLayer::new(jwks_client, "starsky")) - .named_layer(StarskyServer::new(starsky_service)); + .service(PolicyManagementServerStub::new(service)); ``` note: -A real example of a layered service from Starsky. Slightly simplified for the sake of the presentation. +A real example of a layered service. Slightly simplified for the sake of the presentation. + The flow will be the following: -Timeout -> SSRHL -> Tracing -> SSRHL -> Auth -> Starsky service +Timeout -> SSRHL -> Tracing -> SSRHL -> Auth -> PM service --- @@ -403,6 +404,10 @@ note: These are only a few notable features, it provides more for sure +--- + +## Let's build a library with generated Rust code + --- ## Generating code from Proto definitions :gear: @@ -438,7 +443,7 @@ note: First we need to talk about how do we generate code from our protobuf definitions. --- -## Expose the generated code as a library +## Exposing the generated code as a library ```rust // lib.rs @@ -473,6 +478,10 @@ We need to expose the generated code through our lib.rs --- +## Let's build a gRPC application + +--- + ## Filling the gaps ```rust @@ -542,8 +551,12 @@ let server = PolicyManagementServerStub::new( // Implementation of the service PolicyManagementServiceImpl::new(application) - ) - ); + ) + ).add_service( + QuotingServerStub::new( + QuoteServiceImpl::new(application) + ) + ); let listener = TcpListener::bind(("0.0.0.0", grpc_port)).await?; @@ -552,11 +565,14 @@ server.serve(listener).await?; note: -Simple build of a Tonic Server. We will dive into how to add middleware later. +Simple build of a Tonic Server. -Highlight the fact that at the end of the day the gRPC server will be listening to a TCP port like any other HTTP2 server. +- The GrpcServer acts as a Router. +- The GrpcServer doesn't know how to unpack-pack messages, that is handled by each specific server stub. +- The GrpcServer will be listening to a TCP port like an HTTP2 server. --- + ## Building the client ```rust @@ -593,79 +609,6 @@ What if we wanted to add those headers for every request? Now we talk about inte --- -## Health checking gRPC services - -Tonic provides a health check service implementing a standard gRPC health checking protocol. - -[https://github.com/grpc/grpc/blob/master/doc/health-checking.md](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) - -note: - -A GRPC service is used as the health checking mechanism. - -Since it is a GRPC service itself, doing a health check is in the same format as a normal rpc. - -It has rich semantics such as per-service health status. - -The server has full control over the access of the health checking service. - ---- -## Health service definition - -```protobuf -syntax = "proto3"; - -package grpc.health.v1; - -message HealthCheckRequest { - string service = 1; -} - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - SERVICE_UNKNOWN = 3; // Used only by the Watch method. - } - ServingStatus status = 1; -} - -service Health { - rpc Check(HealthCheckRequest) returns (HealthCheckResponse); - rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); -} -``` - -This definition is provided by the official gRPC docs, each language runtime might implement it or not. - -[https://github.com/grpc/grpc/blob/master/doc/health-checking.md](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) ---- -## Enabling the health service - -```rust -use es_policy_grpc::policy_service::v1::PolicyManagementServiceServer as PolicyManagementServerStub; -use tonic_health::server::health_reporter; -use tonic::Server as GrpcServer; - -let (health_reporter, health_service) = health_reporter(); - -health_reporter - .set_serving::>() - .await; - -GrpcServer::builder() - // Add other layers - .layer(..) - .add_service(health_service) - .serve(addr) - .await?; -``` - -note: - -Make it clear that we are using the `tonic-health` crate which doesn't come by default with `tonic`. - --- # Building middleware with Tower @@ -1037,6 +980,116 @@ It is this simple :) --- +## Extras + +Did we get here? :eyes: + +--- + +## Health checking gRPC services + +Tonic provides a health check service implementing a standard gRPC health checking protocol. + +[https://github.com/grpc/grpc/blob/master/doc/health-checking.md](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) + +note: + +A GRPC service is used as the health checking mechanism. + +Since it is a GRPC service itself, doing a health check is in the same format as a normal rpc. + +It has rich semantics such as per-service health status. + +The server has full control over the access of the health checking service. + +--- +## Health service definition + +```protobuf +syntax = "proto3"; + +package grpc.health.v1; + +message HealthCheckRequest { + string service = 1; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + SERVICE_UNKNOWN = 3; // Used only by the Watch method. + } + ServingStatus status = 1; +} + +service Health { + rpc Check(HealthCheckRequest) returns (HealthCheckResponse); + rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); +} +``` + +This definition is provided by the official gRPC docs, each language runtime might implement it or not. + +[https://github.com/grpc/grpc/blob/master/doc/health-checking.md](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) +--- +## Enabling the health service + +```rust +use es_policy_grpc::policy_service::v1::PolicyManagementServiceServer as PolicyManagementServerStub; +use tonic_health::server::health_reporter; +use tonic::Server as GrpcServer; + +let (health_reporter, health_service) = health_reporter(); + +health_reporter + .set_serving::>() + .await; + +GrpcServer::builder() + // Add other layers + .layer(..) + .add_service(health_service) + .serve(addr) + .await?; +``` + +note: + +Make it clear that we are using the `tonic-health` crate which doesn't come by default with `tonic`. + +--- + +## Interceptors + +Interceptors are similar to middleware but with less flexibility. +They allow you to: +- Add/remove/check items in the metadata of each request. +- Cancel a request with a `Status`. +--- + +## Interceptors in practice + +```rust +use es_policy_grpc::policy_service::v1::PolicyManagementServiceServer as PolicyManagementServerStub; +use tonic::{metadata::MetadataValue, Request, Response, Status}; + +fn check_auth(req: Request<()>) -> Result, Status> { + match req.metadata().get(http::AUTHORIZATION) { + Some(t) if is_valid(t) => Ok(req), + _ => Err(Status::unauthenticated("No valid auth token")), + } +} + +let svc = PolicyManagementServerStub::with_interceptor( + PolicyManagementServiceImpl::new(application), + check_auth +); +``` + +--- + # Thank you for your time :heart: