Sistemas Distribuídos - Lab Prático gRPC

3 minute read

Published:

Lab Prático: gRPC em Python – Sistema de Biblioteca

Neste lab, você irá aprender a construir um serviço distribuído utilizando gRPC em Python.

Ao final, você será capaz de:

  • criar um arquivo .proto
  • gerar código automaticamente com gRPC
  • implementar um servidor
  • implementar um cliente
  • realizar chamadas remotas

Estrutura do Projeto

library_grpc/
├── proto/
│   └── library.proto
├── server.py
├── client.py

Instalação

Instale as dependências:

pip install grpcio grpcio-tools protobuf

Passo 1 — Definir o contrato (.proto)

Crie o arquivo:

proto/library.proto

syntax = "proto3";

package library;

enum BookStatus {
  UNKNOWN = 0;
  AVAILABLE = 1;
  BORROWED = 2;
}

message Book {
  string title = 1;
  string author = 2;
  string isbn = 3;
  int32 year = 4;
  BookStatus status = 5;
}

message CreateBookRequest {
  Book book = 1;
}

message CreateBookResponse {
  bool success = 1;
  string message = 2;
}

message ListBooksRequest {
  string author = 1;
}

message ListBooksResponse {
  repeated Book books = 1;
}

service LibraryService {
  rpc CreateBook(CreateBookRequest) returns (CreateBookResponse);
  rpc ListBooks(ListBooksRequest) returns (ListBooksResponse);
}

Entenda o .proto

  • Book: estrutura de dados
  • enum: valores fixos (status)
  • rpc: métodos remotos
  • repeated: lista de objetos

Passo 2 — Gerar código

Execute:

python -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. ./proto/library.proto

Arquivos gerados:

  • library_pb2.py
  • library_pb2_grpc.py

Passo 3 — Implementar o servidor

Arquivo: server.py

from concurrent import futures
import grpc

import library_pb2
import library_pb2_grpc


class LibraryService(library_pb2_grpc.LibraryServiceServicer):

    def __init__(self):
        self.books = []

    def CreateBook(self, request, context):
        book = request.book

        if not book.isbn:
            return library_pb2.CreateBookResponse(
                success=False,
                message="ISBN is required"
            )

        self.books.append(book)

        return library_pb2.CreateBookResponse(
            success=True,
            message="Book created successfully"
        )

    def ListBooks(self, request, context):
        author_filter = request.author.lower()

        result = []

        for book in self.books:
            if author_filter in book.author.lower():
                result.append(book)

        return library_pb2.ListBooksResponse(books=result)


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

    library_pb2_grpc.add_LibraryServiceServicer_to_server(
        LibraryService(), server
    )

    server.add_insecure_port('[::]:50051')
    server.start()

    print("Server running on port 50051")

    server.wait_for_termination()


if __name__ == '__main__':
    serve()

O que o servidor faz

  • armazena livros em memória
  • recebe requisições
  • processa dados
  • retorna respostas

Passo 4 — Implementar o cliente

Arquivo: client.py

import grpc

import library_pb2
import library_pb2_grpc


def print_book(book):
    print(book.title, "-", book.author)


def run():
    channel = grpc.insecure_channel('localhost:50051')
    stub = library_pb2_grpc.LibraryServiceStub(channel)

    stub.CreateBook(
        library_pb2.CreateBookRequest(
            book=library_pb2.Book(
                title="Clean Code",
                author="Robert Martin",
                isbn="123",
                year=2008,
                status=library_pb2.AVAILABLE
            )
        )
    )

    stub.CreateBook(
        library_pb2.CreateBookRequest(
            book=library_pb2.Book(
                title="Distributed Systems",
                author="Tanenbaum",
                isbn="456",
                year=2016,
                status=library_pb2.AVAILABLE
            )
        )
    )

    response = stub.ListBooks(
        library_pb2.ListBooksRequest(author="")
    )

    print("Books:")
    for book in response.books:
        print_book(book)


if __name__ == '__main__':
    run()

Passo 5 — Executar

Terminal 1 (Servidor):

python server.py

Terminal 2 (Cliente):

python client.py

Resultado esperado

Books:
Clean Code - Robert Martin
Distributed Systems - Tanenbaum

Fluxo do sistema

  1. Cliente cria requisição
  2. gRPC envia ao servidor
  3. Servidor processa
  4. Servidor responde
  5. Cliente exibe resultado

Erros comuns

  • não iniciar o servidor
  • não gerar os arquivos .proto
  • erro no caminho do arquivo
  • porta incorreta
  • dependências não instaladas

Exercícios

Exercício 1 — Get Book by ISBN

Implemente:

  • busca por ISBN
  • retorno de um livro

Exercício 2 — Update Book Status

Implemente:

  • alteração de status
  • validação de existência

Exercício 3 — Melhorar Listagem

Adicionar:

  • filtro por title
  • filtro por status

Exercício 4 — Validação

  • impedir ISBN duplicado
  • impedir título vazio