UNIX 104: timeout
Mit Bug 36044 hatten wird das Problem, das eine geöffnete TCP-Verbindung zu unserem Update-Server steckengeblieben ist und damit unsere Tests solange blockiert hat, bis wir sie von Hand abgebrochen haben.
Die genaue Ursache dafür ist unbekannt, aber die Lösung für dieses und ähnliche Problem ist ganz einfach:
- Bei
urllib2.urlopen()
bitte ein timeout angeben. - Ähnliches auch bei direkter Verwendung von
socket.create_connection()
- Global (pro Prozess) könnt ihr auch
socket.setdefaulttimeout()
verwenden, was sich auf alle anderen Bibliotheksfunktionen auswirkt und von daher ggf. unerwünschte Effekte nach sich zieht.
Ein bisschen Hintergrundinformation dazu:
connect()
undrecv()
sind blockierende Funktionen, d.h. sie warten (bis in alle Ewigkeit) darauf, dass die Verbindung zustande kommt bzw. Daten empfangen werden.- In Python wird die Socket-Verbindung per
makefile()
gerne in ein File-ähnliches Objekt umgewandelt. Ein unschuldig aussehendesread()
kann dann schon blockieren. - TCP hat von Haus aus kein Timeout, d.h. eine einmalig geöffnete Verbindung bleibt bis in alle Ewigkeit bestehen. Von daher ist es Aufgabe der Anwendung, ein Timeout einzurichten!
- Apache schließt eine Verbindung nach 5 Sekunden).
ssh
implementiert mitClientAliveInterval
einen ähnlichen Mechanismus.
- Alternativ gibt es noch TCP-KeepAlive, das auf der Transport-Schicht einen Mechanismus implementiert, wo regelmäßig leere TCP-Pakete ausgetauscht werden. Gleichzeitig wird ein Timer auf beiden Seiten gestartet, der bei ausbleiben der Pakete dann den Socket wegen Timeout schließt. Das muss aber per
setsockopt(SOL_SOCKET, SO_KEEPALIVE, 1)
explizit aktiviert werden und funktioniert eben auch nur dann, wenn man direkten Zugriff auf den Socket hat – was bei bei Verwendung vonurllib2
eben nicht hat.
PS: Und selbst ein Timeout von 1 Tag ist besser als gar kein Timeout.
Written on March 11, 2015