DEV Community

fabriciolfj
fabriciolfj

Posted on • Edited on

3

Grpc - Spring Boot

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

@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;
    }

}

Enter fullscreen mode Exit fullscreen mode

Classe para iniciar a comunicação com o server.

@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());
            }
        }));
    }
}
Enter fullscreen mode Exit fullscreen mode

Server

Classe responsável por configurar o server

@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();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Classe responsável por subir o server

@Component
@RequiredArgsConstructor
public class GrpcServerRunner implements CommandLineRunner {

    private final GrpcServer grpcServer;

    @Override
    public void run(String... args) throws Exception {
        grpcServer.start();
        grpcServer.block();
    }
}
Enter fullscreen mode Exit fullscreen mode

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

    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));
    }
Enter fullscreen mode Exit fullscreen mode

Playwright CLI Flags Tutorial

5 Playwright CLI Flags That Will Transform Your Testing Workflow

  • 0:56 --last-failed: Zero in on just the tests that failed in your previous run
  • 2:34 --only-changed: Test only the spec files you've modified in git
  • 4:27 --repeat-each: Run tests multiple times to catch flaky behavior before it reaches production
  • 5:15 --forbid-only: Prevent accidental test.only commits from breaking your CI pipeline
  • 5:51 --ui --headed --workers 1: Debug visually with browser windows and sequential test execution

Learn how these powerful command-line options can save you time, strengthen your test suite, and streamline your Playwright testing experience. Click on any timestamp above to jump directly to that section in the tutorial!

Watch Full Video 📹️

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

If this post resonated with you, feel free to hit ❤️ or leave a quick comment to share your thoughts!

Okay