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:

Ein bisschen Hintergrundinformation dazu:

  • connect() und recv() 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 aussehendes read() 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 mit ClientAliveInterval 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 von urllib2 eben nicht hat.

PS: Und selbst ein Timeout von 1 Tag ist besser als gar kein Timeout.

Written on March 11, 2015