Grpc - Spring Boot
Published: 2021-07-17 15:58:20

Antes de falarmos sobre grpc, precisamos comentar sobre http/2, pois este está presente nesta implementação.
Logo em seguida uma breve introdução referente ao grpc e seu funcionamento. Ao final uma implementação  client/server.
Projeto completo encontra-se aqui: https://github.com/fabriciolfj/grpc-example

## HTTP/2
1. Os dados trafegados são binários, utilizando o GZIP, por padrão.

2. O cabeçalho é stateful, ou seja, guarda estado transacional. Exemplo: primeira requisição envia um conjunto de cabeçalhos, na segunda, envia apenas os alterados. (HPACK)

3. Server push: ao realizar um requisição, o servidor já envia todo o contéudo necessário para renderizar a pagina por exemplo.

4. Multiplexação: com uma conexão tcp aberta, a comunição com o servidor é paralela, ou seja, não espera a requisição anterior terminar para chamar outra, e as respostas vão chegando conforme ficarem prontas.

## GRPC
Desenvolvido pela google, esta implementação tem como objetivo aprimorar a performance da comunicação http.

Podemos utilizar os tipos de contéudos mais conhecidos do mercado, como json ou xml, no entando recomenda-se o uso do proto, devido a sua alta performance para serialização/deserialização.

### Camadas

1. Stub: client chama o servidor através de stubs.
 * camada mais alta
 * gerada a partir de arquivos IDL (interface definition language)
 * arquivos possui extensão .proto

2. Transporte: camada mais baixa, utiliza protocolo http2

### Formas de comunicação
Existem 4 formas de comunicação
1. unary: cliente e servidor (uma request, um response) O canal de comunicação se fecha, após enviar a resposta

2. server-streaming: fluxo de dados por parte do servidor (um request, recebe um fluxo de mensagens). Canal de comunicação do lado do servidor fica aberto, enquanto ouver eventos e serem emitidos.

3. client-streaming: fluxo de dados por parte do cliente (envia um fluxo de mensagens, espera um response)

4. bidirectional-streaming: fluxo de dados por parte de ambos (cliente e servidor, envia um fluxo de mensagens, espera um fluxo de mensagens).


Vamos adotar um unary neste projeto e recomenda-se o uso do grpc entre aplicações e não como rota de acesso a usuários.

### Code
#### Client
Configurando o client, para se comunicar com o server
```java
@Component
@Log4j2
public class GrpcClient {

    @Value("${grpc.server.host:localhost}")
    private String host;

    @Value("${grpc.server.port:9090}")
    private int port;

    private ManagedChannel channel;
    private PersonServiceBlockingStub personServiceBlockingStub;

    public void start() {
        channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();

        personServiceBlockingStub = PersonServiceGrpc.newBlockingStub(channel);
        log.info("gRPC client connected to {}:{}", host, port);
    }

    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
        log.info("gRPC client disconnected successfully.");
    }

    public PersonServiceBlockingStub getSourceServiceStub() {
        return this.personServiceBlockingStub;
    }

}

```
Classe para iniciar a comunicação com o server.
```java
@Component
@Log4j2
public class GrpcClientRunner implements CommandLineRunner {

    @Autowired
    private GrpcClient grpcClient;

    @Override
    public void run(String... args) throws Exception {
        grpcClient.start();

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                grpcClient.shutdown();
            } catch (InterruptedException e) {
                log.error("Client stoppd with error: {}", e.getMessage());
            }
        }));
    }
}
```

#### Server
Classe responsável por configurar o server
```java
@Component
@Log4j2
public class GrpcServer {

    @Value("${grpc.server.port:9090}")
    private int port;
    private Server server;
    private PersonService personService;
    private ExceptionInterceptor exceptionInterceptor;

    public GrpcServer(PersonService personService, ExceptionInterceptor exceptionInterceptor) {
        this.personService = personService;
        this.exceptionInterceptor = exceptionInterceptor;
    }

    public void start() throws IOException, InterruptedException {
        log.info("gRPC server is starting on port: {}.", port);
        server = ServerBuilder.forPort(port)
                .addService(personService)
                .intercept(exceptionInterceptor)
                .build().start();
        log.info("gRPC server started and listening on port: {}.", port);
        log.info("Following service are available: ");
        server.getServices().stream()
                .forEach(s -> log.info("Service Name: {}", s.getServiceDescriptor().getName()));
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("Shutting down gRPC server.");
            GrpcServer.this.stop();
            log.info("gRPC server shut down successfully.");
        }));
    }

    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    public void block() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }
}
```
Classe responsável por subir o server
```java
@Component
@RequiredArgsConstructor
public class GrpcServerRunner implements CommandLineRunner {

    private final GrpcServer grpcServer;

    @Override
    public void run(String... args) throws Exception {
        grpcServer.start();
        grpcServer.block();
    }
}
```

Exemplo de uma chamada ao um service, que envia a mensagem ao grpc server, através do grpc client.

```java
    private final GrpcClient grpcClient;

    public PersonResponseDTO create(final PersonRequestDTO requestDTO) {
        var request = PersonMapper.toRequest(requestDTO);
        log.info("Request create: {}", request.toString());
        return PersonMapper.toResponse(grpcClient.getSourceServiceStub().create(request));
    }
```