5.9 KiB
5.9 KiB
Windows Socket-Fehler Fix Dokumentation
Problem
Bei der Entwicklung auf Windows-Systemen tritt ein Socket-Fehler beim Flask Auto-Reload auf:
OSError: [WinError 10038] Ein Vorgang bezog sich auf ein Objekt, das kein Socket ist
Ursache
Das Problem entsteht durch:
- Flask's Auto-Reload-Feature startet den Server neu wenn Dateien geändert werden
- Der Queue Manager startet einen Daemon-Thread für Drucker-Überwachung
- Beim Neustart wird der alte Thread nicht ordnungsgemäß beendet
- Socket-Ressourcen werden nicht korrekt freigegeben
- Windows reagiert besonders empfindlich auf nicht geschlossene Sockets
Lösung
Implementierung eines mehrstufigen Fixes:
1. Verbesserter Queue Manager (utils/queue_manager.py
)
- Threading.Event: Verwendung von
threading.Event
statttime.sleep()
für unterbrechbares Warten - Non-Daemon Threads: Threads werden als non-daemon erstellt für bessere Kontrolle
- Signal-Handler: Windows-spezifische Signal-Handler für SIGINT, SIGTERM, SIGBREAK
- Thread-Locks: Thread-sichere Operationen mit
threading.Lock()
- Ordnungsgemäße Beendigung: Timeout-basierte Thread-Beendigung mit Logging
# Verbessertes Shutdown-Handling
def stop(self):
with self._lock:
if self.is_running:
self.is_running = False
self.shutdown_event.set()
if self.monitor_thread and self.monitor_thread.is_alive():
self.monitor_thread.join(timeout=10)
2. Windows-spezifische Fixes (utils/windows_fixes.py
)
- Socket-Patches: SO_REUSEADDR für Socket-Wiederverwendung
- Thread-Manager: Zentrale Verwaltung aller Threads
- Signal-Handler: SIGBREAK-Unterstützung für Windows
- Umgebungs-Optimierung: UTF-8 Encoding und Thread-Pool-Einstellungen
def fix_windows_socket_issues():
# Socket-Wiederverwendung aktivieren
socket.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
3. Verbesserte App-Startup-Logik (app.py
)
- Prozess-Erkennung: Queue Manager nur im Hauptprozess starten
- Signal-Handling: Windows-kompatible Signal-Handler
- Graceful Shutdown: Koordinierte Beendigung aller Komponenten
- Auto-Reload-Erkennung: Spezielle Behandlung für Flask Reloader
# Nur im Hauptprozess starten (nicht bei Flask Auto-Reload)
if not debug_mode or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
queue_manager = start_queue_manager()
Technische Details
Threading-Verbesserungen
# Alte Implementierung (problematisch)
while self.is_running:
self._check_waiting_jobs()
time.sleep(self.check_interval) # Nicht unterbrechbar
# Neue Implementierung (robust)
while self.is_running and not self.shutdown_event.is_set():
self._check_waiting_jobs()
if self.shutdown_event.wait(timeout=self.check_interval):
break # Sofort beenden bei Shutdown-Signal
Signal-Handling
# Windows-spezifische Signale
if os.name == 'nt':
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGBREAK, signal_handler) # Windows-spezifisch
Socket-Optimierung
# Gepatchte bind-Methode für Socket-Wiederverwendung
def patched_bind(self, address):
try:
self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except:
pass
return self._bind_orig(address)
Vorteile der Lösung
1. Robustheit
- Threads werden immer ordnungsgemäß beendet
- Socket-Ressourcen werden korrekt freigegeben
- Keine hängenden Prozesse bei Auto-Reload
2. Windows-Kompatibilität
- Spezielle Behandlung für Windows-Eigenarten
- SIGBREAK-Signal-Unterstützung
- SO_REUSEADDR für Socket-Wiederverwendung
3. Entwicklerfreundlichkeit
- Auto-Reload funktioniert ohne Fehler
- Detailliertes Logging für Debugging
- Automatische Cleanup-Prozesse
4. Produktions-Tauglichkeit
- Graceful Shutdown in Produktionsumgebung
- Thread-sichere Operationen
- Robuste Fehlerbehandlung
Konfiguration
Environment-Variablen
# Für bessere Windows-Kompatibilität
PYTHONIOENCODING=utf-8
PYTHONUTF8=1
WERKZEUG_RUN_MAIN=true
Flask-Konfiguration (Debug-Modus)
if os.name == 'nt': # Windows
app.run(
host="0.0.0.0",
port=5000,
debug=True,
threaded=True,
use_reloader=True,
reloader_interval=1,
passthrough_errors=False
)
Monitoring
Log-Ausgaben
✅ Printer Queue Manager erfolgreich gestartet
🔄 Queue-Überwachung gestartet (Intervall: 120 Sekunden)
🛑 Signal 2 empfangen - fahre System herunter...
🔄 Beende Queue Manager...
✅ Monitor-Thread erfolgreich beendet
Gesundheitsprüfung
def is_healthy(self) -> bool:
return (self.is_running and
self.monitor_thread is not None and
self.monitor_thread.is_alive() and
not self.shutdown_event.is_set())
Bekannte Probleme und Workarounds
Problem: Thread bleibt hängen
Lösung: Timeout-basierte Thread-Beendigung mit Warnung
Problem: Socket bereits in Verwendung
Lösung: SO_REUSEADDR aktivieren
Problem: Auto-Reload startet Queue Manager mehrfach
Lösung: Prozess-Erkennung über WERKZEUG_RUN_MAIN
Testing
# Test mit Debug-Modus
python app.py --debug
# Test mit Produktions-Modus
python app.py
# Überwachung der Logs
tail -f logs/app/app.log | grep "Queue Manager"
Wartung
- Regelmäßige Überprüfung der Thread-Gesundheit
- Monitoring der Socket-Verwendung
- Log-Analyse für hanging Threads
- Performance-Überwachung der Thread-Beendigung
Fazit
Dieser Fix behebt das Windows Socket-Problem vollständig durch:
- Ordnungsgemäße Thread-Verwaltung
- Windows-spezifische Socket-Behandlung
- Robuste Signal-Handler
- Graceful Shutdown-Mechanismen
Das System ist jetzt sowohl für Entwicklung als auch Produktion auf Windows-Systemen stabil einsetzbar.