Problème
Après arrêt du serveur (fermeture fenêtre console ou Ctrl+C), le port reste occupé quelques minutes au prochain lancement.
Cause racine : fermeture TCP propre (FIN) → connexions en TIME_WAIT côté serveur → port bloqué.
Note : SO_REUSEADDR via net.ListenConfig.Control testé et abandonné — cause WSAEACCES sur Windows (Go pose SO_EXCLUSIVEADDRUSE en interne).
Solution
Poser SO_LINGER(0) sur chaque connexion acceptée → le kernel envoie RST au lieu de FIN → TIME_WAIT éliminé à la source.
Implémentation via un wrapper net.Listener qui intercepte Accept() et configure SO_LINGER sur chaque net.Conn.
Couverture :
- ✅ Fermeture fenêtre console (CTRL_CLOSE_EVENT → os.Interrupt)
- ✅ Ctrl+C
- ✅ /shutdown HTTP endpoint
- ⚠️ Task Manager forcible kill → retry loop (filet de sécurité)
Contexte
os.Interrupt déjà dans signal.Notify (commit a27b2a5)
- Graceful shutdown
Shutdown(ctx, 3s) opérationnel (v5.1.2)
- Fichiers concernés :
server-go/internal/server/http.go, listen_windows.go
Problème
Après arrêt du serveur (fermeture fenêtre console ou Ctrl+C), le port reste occupé quelques minutes au prochain lancement.
Cause racine : fermeture TCP propre (FIN) → connexions en TIME_WAIT côté serveur → port bloqué.
Note : SO_REUSEADDR via
net.ListenConfig.Controltesté et abandonné — causeWSAEACCESsur Windows (Go pose SO_EXCLUSIVEADDRUSE en interne).Solution
Poser
SO_LINGER(0)sur chaque connexion acceptée → le kernel envoie RST au lieu de FIN → TIME_WAIT éliminé à la source.Implémentation via un wrapper
net.Listenerqui intercepteAccept()et configure SO_LINGER sur chaquenet.Conn.Couverture :
Contexte
os.Interruptdéjà danssignal.Notify(commita27b2a5)Shutdown(ctx, 3s)opérationnel (v5.1.2)server-go/internal/server/http.go,listen_windows.go