O teu microsserviço não arranca em local
Um microsserviço que não levanta na tua máquina quase nunca é uma falha do teu código. É uma de seis coisas, e a maior parte do tempo perdido vai-se em não saber qual das seis. Esta página ordena-as por frequência e dá a verificação que descarta cada uma em menos de um minuto.
A ordem importa: descarta de fora para dentro
A tentação é abrir o código. É quase sempre a última coisa a olhar, porque o mesmo commit arranca no ambiente partilhado. O que mudou não é o serviço: é o que o rodeia.
| # | Causa | O que vais ver | Verificação |
|---|---|---|---|
| 1 | Porta ocupada | address already in use, EADDRINUSE, ou o processo morre logo |
lsof -i :8080 |
| 2 | Infraestrutura em baixo | connection refused para a 5432, a 9092 ou a 6379 |
docker ps |
| 3 | Arrancou cedo demais | Às vezes arranca e às vezes não, com o mesmo código | Volta a lançá-lo à mão; se agora vai, era a ordem |
| 4 | Configuração incompleta | Falha a construir um bean ou a ler uma propriedade | Compara as variáveis com as do ambiente partilhado |
| 5 | Base de dados sem esquema | relation … does not exist, ou migrações que falham |
Liga-te à mão e lista as tabelas |
| 6 | Versão do runtime | UnsupportedClassVersionError, sintaxe que não compila |
java -version, node -v |
1. A porta já está ocupada
É a causa mais frequente e a que mais depressa se descarta. Todos os projetos da mesma tecnologia trazem a mesma porta por omissão: a 8080 na JVM, a 3000 em Node, a 5432 em Postgres. Basta ter duas coisas abertas.
# macOS e Linux
lsof -i :8080
# Windows
netstat -ano | findstr :8080
Se aparecer alguma coisa, já tens o culpado. O incómodo não é matá-lo: é que amanhã volta a acontecer com outra porta, e que o serviço que o chama continua a apontar para a antiga.
2. A infraestrutura não está de pé (ou não está pronta)
docker ps e vê se estão o Kafka, o Redis e o Postgres. Mas atenção à
armadilha: «de pé» não é «pronto». Um contentor tem PID desde o primeiro
segundo, e o Postgres lá dentro pode demorar mais vinte a aceitar ligações. Se o teu
serviço arrancar nesse intervalo, vê um connection refused e morre.
É exatamente o que o depends_on do compose não resolve: espera pelo
contentor, não pelo serviço. Por isso é preciso um healthcheck e uma condição
service_healthy, e por isso o mesmo compose arranca numa máquina rápida e não
numa lenta.
3. Arrancou antes daquilo a que chama
O sintoma que o denuncia: às vezes arranca e às vezes não, com o mesmo código. Isso é uma corrida, não um erro. O teu serviço regista-se ou pede alguma coisa ao arrancar, e quem lha tem de dar ainda não estava a responder.
Lançá-lo outra vez à mão confirma-o em dez segundos: se agora vai, não era o código.
4. Falta-lhe configuração que na nuvem alguém lhe dá
No ambiente partilhado, essas variáveis são postas pelo deploy. Na tua máquina pô-las tu, e o problema não é pô-las: é saber quais. A lista costuma viver num ficheiro de deploy que não está no teu repositório.
Reconhece-se o erro porque o serviço morre a construir-se, não a servir: um bean que não se consegue criar, uma propriedade obrigatória em falta, um cliente que não encontra o seu URL base.
5. A base de dados existe mas está vazia
Contentor de pé, ligação correta, e mesmo assim relation "orders" does not
exist. Falta correr as migrações, ou correram contra outra base.
A regra que convém não quebrar enquanto persegues isto: não lances migrações
contra o ambiente partilhado. Um flyway migrate disparado sem querer
contra a base comum é uma tarde perdida para toda a equipa, não só para ti.
6. A versão do runtime não é a que o projeto espera
Última da lista porque é a menos frequente, mas a que mais despista quando acontece: a
mensagem fala de classes ou de sintaxe e parece um problema de código. Se o projeto
declara a sua versão (.sdkmanrc, .nvmrc, a propriedade do
Maven), compara-a com a que tens.
E quando arranca, começa o problema a sério
As seis causas de cima são de um serviço. Quando arrancam três e têm de falar
entre si, aparece a que não está em nenhuma lista: para onde chama cada
um. O URL correto depende de onde corre quem chama —um processo nativo chega a um
contentor por localhost, um contentor chega a outro pelo nome do serviço, e
um contentor que chama algo nativo precisa do nome especial do host—, por isso a mesma
dependência tem três URLs consoante como esteja a correr cada extremo.
É isso que acaba escrito à mão na configuração de um repositório que não é teu, com a nota mental de não o comitares.
Como o Aseptic o tira do caminho
O Aseptic não adivinha porque falha o teu código, e esta página não o vende como tal. O que faz é que cinco das seis causas deixem de acontecer:
- As portas que colidem são remapeadas sozinhas, e o valor novo é o que recebem os que chamam — não é preciso avisar ninguém.
- A infraestrutura é levantada pela app, que espera que esteja saudável, não que tenha PID.
- O cenário arranca por ordem de dependência, esperando pela saúde de cada um antes de seguir.
- A configuração é injetada ao arrancar como propriedades
-Dou variáveis de ambiente, por isso não há ficheiro para editar nem nada de que lembrar-se de reverter. - Os URLs entre serviços são reescritos com a perspetiva correta consoante onde corre cada extremo.
A sexta —a versão do runtime— continua a ser tua, e assim deve ser: é o teu projeto que declara com que se constrói.
Se isto te acontece todos os dias, o ponto de partida é o que precisa um ambiente local de microsserviços, e daí levantar só a parte que te interessa.
Perguntas frequentes
Porque é que o meu microsserviço arranca no ambiente partilhado e não na minha máquina?
Quase sempre porque no ambiente partilhado alguém resolveu por ti as quatro coisas que em local resolves tu: a infraestrutura, a ordem de arranque, os URLs entre serviços e os dados. O serviço não mudou; mudou o que o rodeia.
O log diz «connection refused» mas o contentor está de pé. Porquê?
Porque «de pé» não é «pronto». Um contentor tem PID desde o primeiro segundo e o serviço lá dentro pode demorar mais vinte a aceitar ligações. O depends_on do compose espera pelo contentor, não pela saúde.
Como sei se o problema é a porta?
Vê quem a tem: lsof -i :8080 em macOS ou Linux, netstat -ano | findstr :8080 em Windows. Se aparecer alguma coisa, o erro não é do teu código.
Vale a pena resolver isto ou viver com o LOCAL_SETUP.md?
Depende de quantas vezes por dia o pagas. Um documento de quarenta passos custa pouco a escrever e muito a manter: falha de forma diferente em cada máquina e ninguém o atualiza quando muda uma flag.