O TicketFast é um projeto desenvolvido em Java com Spring Boot para simular e resolver um dos problemas mais clássicos e críticos em sistemas de venda de ingressos (como Ticketmaster) e e-commerce: a Race Condition (Condição de Corrida) e o risco de Double-Booking (Vendas Duplicadas).
O objetivo deste projeto foi validar, através de testes de estresse com o K6, o comportamento do sistema sob carga extrema em dois cenários: uma abordagem ingênua (vulnerável) e uma arquitetura robusta utilizando Trava Distribuída (Distributed Lock) com Redis (Redisson) combinada com Lock Otimista (@Version) no PostgreSQL.
- Java 21 & Spring Boot 4.x
- Spring Data JPA (Camada de Persistência)
- PostgreSQL (Banco de dados relacional)
- Redis & Redisson Core (v3.31.0) (Gerenciamento de travas em memória)
- Flyway (Evolução e migração do esquema do banco)
- Lombok (Produtividade e código limpo)
- K6 (Ferramenta de testes de carga e estresse)
- Docker & Docker Compose (Containerização do Banco e Cache)
O projeto segue os princípios de separação de conceitos em camadas claras:
com.challengers.ticketfast
├── api
│ ├── controllers # Endpoints HTTP (REST)
│ └── dtos # Objetos de transferência de dados (Records)
├── domain
│ ├── model # Entidades de negócio puras (Evento, Assento, Venda)
│ └── repository # Interfaces Spring Data JPA
├── services
│ ├── VendaService.java # Orquestrador do fluxo e trava do Redis
│ └── ExecutarVendaTransaction.java # Camada isolada para transação isolada do banco
└── infrastructure
└── config # Configurações de infraestrutura (Redis/Redisson)
O teste de estresse consistiu em colocar 100 usuários virtuais concorrentes tentando comprar exatamente o mesmo assento físico (ID 1) simultaneamente durante uma janela de 5 segundos.
-
Abordagem: O código lia o status do assento (LIVRE), esperava um pequeno delay de processamento (50ms) e salvava a venda no banco de dados, sem travas.
-
Resultado no K6: O banco de dados foi corrompido. Múltiplas vendas legítimas (Status 201) foram geradas para o mesmo assento, resultando em um grave erro de negócio (Double-Booking).
-
Abordagem: Implementada uma "catraca eletrônica" com o Redisson (lock.tryLock). Apenas a thread que obtém a chave única em memória RAM entra na transação do banco. Como proteção secundária (Defesa em Profundidade), a tabela de assentos utiliza o mecanismo de @Version do JPA.
-
Resultado no K6: Apenas 1 venda foi efetuada com sucesso. As outras 99 requisições foram rejeitadas de forma ultra rápida na camada de memória pelo Redis (Retornando Status 409), poupando o pool de conexões do PostgreSQL e garantindo 100% de integridade dos dados.
Certifique-se de ter o Docker instalado e rode na raiz do projeto:
docker compose up -dAs migrations do Flyway aplicarão o esquema e injetarão a carga inicial de testes automaticamente (1 evento e 10 assentos). Se necessário resetar a base para um novo teste limpo, execute:
docker compose down -v
docker compose up -dInicie a aplicação Spring Boot através da sua IDE de preferência ou via terminal.
Com a aplicação rodando na porta 8080, execute o script do K6 contido na raiz:
k6 run teste-concorrencia.jsAbra seu cliente SQL (ex: DBeaver) e verifique se o banco se manteve íntegro:
SELECT count(*) FROM vendas WHERE assento_id = 1;
-- O resultado deve ser rigorosamente 1.