Votre microservice ne démarre pas en local
Un microservice qui ne démarre pas sur votre machine n'est presque jamais un bug de votre code. C'est l'une de six choses, et l'essentiel du temps perdu part en ne pas savoir laquelle des six. Cette page les classe par fréquence et donne la vérification qui écarte chacune en moins d'une minute.
L'ordre compte : écartez de l'extérieur vers l'intérieur
La tentation est d'ouvrir le code. C'est presque toujours la dernière chose à regarder, parce que le même commit démarre dans l'environnement partagé. Ce qui a changé, ce n'est pas le service : c'est ce qui l'entoure.
| # | Cause | Ce que vous verrez | Vérification |
|---|---|---|---|
| 1 | Port déjà occupé | address already in use, EADDRINUSE, ou le processus meurt aussitôt |
lsof -i :8080 |
| 2 | Infrastructure en panne | connection refused vers le 5432, le 9092 ou le 6379 |
docker ps |
| 3 | Démarré trop tôt | Parfois il démarre, parfois non, avec le même code | Relancez-le à la main ; si ça marche maintenant, c'était l'ordre |
| 4 | Configuration incomplète | Échoue en construisant un bean ou en lisant une propriété | Comparez les variables avec celles de l'environnement partagé |
| 5 | Base de données sans schéma | relation … does not exist, ou des migrations qui échouent |
Connectez-vous à la main et listez les tables |
| 6 | Version du runtime | UnsupportedClassVersionError, syntaxe qui ne compile pas |
java -version, node -v |
1. Le port est déjà occupé
C'est la cause la plus fréquente et la plus rapide à écarter. Tous les projets d'une même technologie arrivent avec le même port par défaut : le 8080 sur la JVM, le 3000 sur Node, le 5432 sur Postgres. Il suffit d'avoir deux choses ouvertes.
# macOS et Linux
lsof -i :8080
# Windows
netstat -ano | findstr :8080
Si quelque chose apparaît, vous avez le coupable. Le pénible n'est pas de le tuer : c'est que demain cela recommence sur un autre port, et que le service qui l'appelle pointe toujours vers l'ancien.
2. L'infrastructure n'est pas démarrée (ou pas prête)
docker ps et regardez si Kafka, Redis et Postgres sont là. Mais attention au
piège : « démarré » n'est pas « prêt ». Un conteneur a un PID dès la
première seconde, et le Postgres à l'intérieur peut mettre vingt de plus à accepter des
connexions. Si votre service démarre dans ce creux, il voit un
connection refused et meurt.
C'est exactement ce que le depends_on de compose ne résout pas : il
attend le conteneur, pas le service. D'où la nécessité d'un healthcheck et
d'une condition service_healthy, et d'où le fait que le même compose démarre
sur une machine rapide et pas sur une lente.
3. Il a démarré avant ce qu'il appelle
Le symptôme qui trahit : parfois il démarre et parfois non, avec le même code. C'est une course, pas une erreur. Votre service s'enregistre ou demande quelque chose au démarrage, et celui qui doit le lui donner ne répondait pas encore.
Le relancer à la main le confirme en dix secondes : si ça marche maintenant, ce n'était pas le code.
4. Il lui manque une configuration que le cloud lui donne
Dans l'environnement partagé, ces variables viennent du déploiement. Sur votre machine c'est vous qui les mettez, et le problème n'est pas de les mettre : c'est de savoir lesquelles. La liste vit d'habitude dans un fichier de déploiement qui n'est pas dans votre dépôt.
On reconnaît l'erreur parce que le service meurt en se construisant, pas en servant : un bean impossible à créer, une propriété obligatoire manquante, un client qui ne trouve pas son URL de base.
5. La base de données existe mais elle est vide
Conteneur debout, connexion correcte, et pourtant relation "orders" does not
exist. Il manque de passer les migrations, ou elles ont tourné contre une autre
base.
La règle à ne pas enfreindre pendant que vous cherchez : ne lancez pas de
migrations contre l'environnement partagé. Un flyway migrate tiré
par mégarde contre la base commune, c'est un après-midi perdu pour toute l'équipe, pas
seulement pour vous.
6. La version du runtime n'est pas celle qu'attend le projet
Dernière de la liste parce que c'est la moins fréquente, mais celle qui égare le plus
quand elle arrive : le message parle de classes ou de syntaxe et ressemble à un problème
de code. Si le projet déclare sa version (.sdkmanrc, .nvmrc, la
propriété Maven), comparez-la avec la vôtre.
Et quand il démarre, le vrai problème commence
Les six causes ci-dessus concernent un service. Quand trois démarrent et doivent
se parler, apparaît celle qui n'est sur aucune liste : où appelle chacun.
La bonne URL dépend de l'endroit où tourne l'appelant —un processus natif atteint un
conteneur par localhost, un conteneur en atteint un autre par le nom du
service, et un conteneur qui appelle quelque chose de natif a besoin du nom spécial de
l'hôte—, donc la même dépendance a trois URLs selon la façon dont tourne chaque
extrémité.
C'est ce qui finit écrit à la main dans la configuration d'un dépôt qui n'est pas le vôtre, avec la note mentale de ne pas le commiter.
Comment Aseptic l'écarte du chemin
Aseptic ne devine pas pourquoi votre code échoue, et cette page ne le vend pas comme tel. Ce qu'il fait, c'est que cinq des six causes cessent de se produire :
- Les ports qui entrent en collision sont remappés tout seuls, et c'est la nouvelle valeur que reçoivent les appelants — personne n'a à être prévenu.
- L'infrastructure est démarrée par l'app, qui attend qu'elle soit saine, pas qu'elle ait un PID.
- Le scénario démarre dans l'ordre des dépendances, en attendant la santé de chacun avant de continuer.
- La configuration est injectée au démarrage sous forme de propriétés
-Dou de variables d'environnement, donc aucun fichier à éditer et rien à penser à annuler. - Les URLs entre services sont réécrites avec la bonne perspective selon où tourne chaque extrémité.
La sixième —la version du runtime— reste la vôtre, et c'est bien ainsi : c'est votre projet qui déclare avec quoi il se construit.
Si cela vous arrive tous les jours, le point de départ est ce dont a besoin un environnement local de microservices, et de là démarrer seulement la partie qui vous intéresse.
Questions fréquentes
Pourquoi mon microservice démarre dans l'environnement partagé et pas sur ma machine ?
Presque toujours parce que dans l'environnement partagé quelqu'un a résolu pour vous les quatre choses que vous résolvez vous-même en local : l'infrastructure, l'ordre de démarrage, les URLs entre services et les données. Le service n'a pas changé ; ce qui l'entoure, si.
Le log dit « connection refused » mais le conteneur est démarré. Pourquoi ?
Parce que « démarré » n'est pas « prêt ». Un conteneur a un PID dès la première seconde et le service à l'intérieur peut mettre vingt de plus à accepter des connexions. Le depends_on de compose attend le conteneur, pas la santé.
Comment savoir si le problème vient du port ?
Regardez qui l'occupe : lsof -i :8080 sur macOS ou Linux, netstat -ano | findstr :8080 sur Windows. Si quelque chose apparaît, l'erreur n'est pas dans votre code.
Vaut-il la peine de corriger cela ou de vivre avec le LOCAL_SETUP.md ?
Cela dépend du nombre de fois par jour que vous le payez. Un document de quarante étapes coûte peu à écrire et beaucoup à maintenir : il échoue différemment sur chaque machine et personne ne le met à jour quand une option change.