Il tuo microservizio non parte in locale
Un microservizio che non si alza sulla tua macchina non è quasi mai un bug del tuo codice. È una di sei cose, e la maggior parte del tempo perso se ne va nel non sapere quale delle sei. Questa pagina le ordina per frequenza e dà la verifica che esclude ciascuna in meno di un minuto.
L'ordine conta: escludi dall'esterno verso l'interno
La tentazione è aprire il codice. È quasi sempre l'ultima cosa da guardare, perché lo stesso commit parte nell'ambiente condiviso. Quello che è cambiato non è il servizio: è ciò che lo circonda.
| # | Causa | Che cosa vedrai | Verifica |
|---|---|---|---|
| 1 | Porta già occupata | address already in use, EADDRINUSE, o il processo muore subito |
lsof -i :8080 |
| 2 | Infrastruttura giù | connection refused verso la 5432, la 9092 o la 6379 |
docker ps |
| 3 | Partito troppo presto | A volte parte e a volte no, con lo stesso codice | Rilancialo a mano; se ora va, era l'ordine |
| 4 | Configurazione incompleta | Fallisce costruendo un bean o leggendo una property | Confronta le variabili con quelle dell'ambiente condiviso |
| 5 | Database senza schema | relation … does not exist, o migrazioni che falliscono |
Collegati a mano ed elenca le tabelle |
| 6 | Versione del runtime | UnsupportedClassVersionError, sintassi che non compila |
java -version, node -v |
1. La porta è già occupata
È la causa più frequente e la più rapida da escludere. Tutti i progetti della stessa tecnologia arrivano con la stessa porta predefinita: la 8080 sulla JVM, la 3000 su Node, la 5432 su Postgres. Basta avere due cose aperte.
# macOS e Linux
lsof -i :8080
# Windows
netstat -ano | findstr :8080
Se compare qualcosa, hai il colpevole. La scomodità non è ucciderlo: è che domani ricapita con un'altra porta, e che il servizio che lo chiama continua a puntare alla vecchia.
2. L'infrastruttura non è su (o non è pronta)
docker ps e guarda se ci sono Kafka, Redis e Postgres. Ma attenzione alla
trappola: «su» non è «pronto». Un container ha un PID dal primo secondo,
e il Postgres al suo interno può metterci altri venti ad accettare connessioni. Se il tuo
servizio parte in quella finestra, vede un connection refused e muore.
È esattamente ciò che il depends_on di compose non risolve: aspetta
il container, non il servizio. Per questo serve un healthcheck e una
condizione service_healthy, e per questo lo stesso compose parte su una
macchina veloce e non su una lenta.
3. È partito prima di ciò che chiama
Il sintomo che lo tradisce: a volte parte e a volte no, con lo stesso codice. Quella è una corsa, non un errore. Il tuo servizio si registra o chiede qualcosa all'avvio, e chi glielo deve dare non stava ancora rispondendo.
Rilanciarlo a mano lo conferma in dieci secondi: se ora va, non era il codice.
4. Gli manca configurazione che nel cloud qualcuno gli dà
Nell'ambiente condiviso quelle variabili le mette il deploy. Sulla tua macchina le metti tu, e il problema non è metterle: è sapere quali. L'elenco di solito vive in un file di deploy che non sta nel tuo repository.
L'errore si riconosce perché il servizio muore mentre si costruisce, non mentre serve: un bean che non si riesce a creare, una property obbligatoria mancante, un client che non trova il suo URL base.
5. Il database esiste ma è vuoto
Container su, connessione corretta, e ciononostante relation "orders" does not
exist. Mancano le migrazioni, o sono girate contro un altro database.
La regola che conviene non infrangere mentre lo insegui: non lanciare migrazioni
contro l'ambiente condiviso. Un flyway migrate sparato per sbaglio
contro il database comune è un pomeriggio perso per tutto il team, non solo per te.
6. La versione del runtime non è quella che il progetto si aspetta
Ultima della lista perché è la meno frequente, ma quella che devia di più quando succede:
il messaggio parla di classi o di sintassi e sembra un problema di codice. Se il progetto
dichiara la sua versione (.sdkmanrc, .nvmrc, la property di
Maven), confrontala con quella che hai.
E quando parte, comincia il problema vero
Le sei cause qui sopra riguardano un servizio. Quando ne partono tre e devono
parlarsi, compare quella che non è in nessun elenco: dove chiama
ciascuno. L'URL corretto dipende da dove gira chi chiama —un processo nativo
raggiunge un container tramite localhost, un container ne raggiunge un altro
tramite il nome del servizio, e un container che chiama qualcosa di nativo ha bisogno del
nome speciale dell'host—, quindi la stessa dipendenza ha tre URL a seconda di come sta
girando ciascun estremo.
È questo che finisce scritto a mano nella configurazione di un repository che non è tuo, con l'appunto mentale di non committarlo.
Come Aseptic lo toglie di mezzo
Aseptic non indovina perché il tuo codice fallisce, e questa pagina non lo vende come tale. Quello che fa è che cinque delle sei cause smettano di verificarsi:
- Le porte che collidono vengono rimappate da sole, e il valore nuovo è quello che ricevono i chiamanti — non c'è da avvisare nessuno.
- L'infrastruttura la avvia l'app, che aspetta che sia sana, non che abbia un PID.
- Lo scenario parte in ordine di dipendenza, aspettando la salute di ciascuno prima di proseguire.
- La configurazione viene iniettata all'avvio come property
-Do variabili d'ambiente, quindi non c'è nessun file da modificare né nulla da ricordarsi di annullare. - Gli URL fra i servizi vengono riscritti con la prospettiva giusta a seconda di dove gira ciascun estremo.
La sesta —la versione del runtime— resta tua, ed è giusto così: è il tuo progetto che dichiara con cosa si costruisce.
Se ti capita ogni giorno, il punto di partenza è che cosa serve a un ambiente locale di microservizi, e da lì avviare solo la parte che ti interessa.
Domande frequenti
Perché il mio microservizio parte nell'ambiente condiviso e non sulla mia macchina?
Quasi sempre perché nell'ambiente condiviso qualcuno ha risolto per te le quattro cose che in locale risolvi tu: l'infrastruttura, l'ordine di avvio, gli URL fra i servizi e i dati. Il servizio non è cambiato; è cambiato ciò che lo circonda.
Il log dice «connection refused» ma il container è su. Perché?
Perché «su» non è «pronto». Un container ha un PID dal primo secondo e il servizio al suo interno può metterci altri venti ad accettare connessioni. Il depends_on di compose aspetta il container, non la salute.
Come faccio a sapere se il problema è la porta?
Guarda chi la tiene: lsof -i :8080 su macOS o Linux, netstat -ano | findstr :8080 su Windows. Se compare qualcosa, l'errore non è nel tuo codice.
Vale la pena sistemare questo o convivere con il LOCAL_SETUP.md?
Dipende da quante volte al giorno lo paghi. Un documento di quaranta passi costa poco a scriverlo e molto a mantenerlo: fallisce in modo diverso su ogni macchina e nessuno lo aggiorna quando cambia una flag.