Socket.io: Safari beendet die Web-Socket-Verbindung aufgrund von Inaktivität, wenn die Seite nicht scharfgestellt ist

Erstellt am 25. Apr. 2017  ·  26Kommentare  ·  Quelle: socketio/socket.io

Du möchtest:

  • [x] einen Fehler melden
  • [] fordere eine Funktion an

Aktuelles Verhalten

Ich bin mir nicht sicher, ob dies ein bekanntes Problem ist (ich habe versucht zu suchen, aber nichts gefunden). Safari für Mac scheint Websocket-Verbindungen aufgrund von Inaktivität / Leerlauf stillschweigend zu trennen, wenn die Seite / Registerkarte nicht scharfgestellt ist.

Schritte zum Reproduzieren (wenn das aktuelle Verhalten ein Fehler ist)

Stellen Sie sicher, dass die Registerkarte / Seite von Safari nicht im Fokus steht. Websocket-Ereignisse protokollieren.

Erwartetes Verhalten

Websockets sollten über die Heartbeat-Funktion am Leben erhalten werden. Dieses Verhalten in anderen Browsern nicht zu sehen, ist so unwahrscheinlich, dass es mein Code ist.

Konfiguration

  • Betriebssystem: Mac OSX 10.12.4 (16E195)
  • Browser: Safari 10.1 (12603.1.30.0.34)
  • socket.io version: 1.7.3

Andere Informationen (z. B. Stacktraces, verwandte Probleme, Vorschläge zur Behebung)

Ist dies möglicherweise eine Art Energiesparfunktion, die den Herzschlag außer Kraft setzt / ignoriert?

bug

Hilfreichster Kommentar

Ich denke, das liegt daran, dass die aktuelle Version von socket.io auf dem Client auf setTimeout basiert, was möglicherweise nicht so zuverlässig ist wie erwartet.

Wir werden dies in die Version 3 aufnehmen, da es sich um eine bahnbrechende Änderung handelt.

Siehe auch: https://github.com/primus/primus/issues/348

Alle 26 Kommentare

Das Ausführen eines Servers mit DEBUG = * zeigt Folgendes:
socket.io:client client close with reason ping timeout +0ms
socket.io:socket closing socket - reason ping timeout +0ms

Ich nehme an, dass Safari die Verbindung geschlossen hat, nicht den Socket-Server oder die Client-Instanz. Das Seltsamste ist jedoch, dass ich bemerkt habe, dass Safari manchmal etwa 30 Sekunden bis 1 Minute später wieder eine Verbindung herstellt,

Es scheint, dass es manchmal sporadisch viel später (wie 10 Minuten) wieder verbindet. Wieder völlig inkonsistent unter identischen Testumgebungen.

@twistedpixel Die Verzögerung Quelle ), sodass das Verhalten möglicherweise erklärt wird.

Wie wäre es, wenn Sie gezwungen wären, die Verbindung wiederherzustellen, wenn das Fenster wieder den Fokus erhält?

window.addEventListener("focus", () => socket.connect());

Es kann mit https://github.com/primus/primus/issues/348 zusammenhängen.

Vielen Dank für die Informationen, aber das Hauptproblem ist, dass der Web-Socket permanent verbunden sein muss, da er verwendet wird, um Benachrichtigungen an den Benutzer zu senden, während dieser nicht da ist. Daher ist der Fensterfokus zum erneuten Verbinden nicht ideal.

Ich denke, es ist tatsächlich etwas problematischeres für meine Maschine / Installation. Ich habe das Verhalten ursprünglich auf meinem iMac bemerkt, also habe ich beschlossen, mein MacBook nur mit einer neuen Version von Safari zu löschen, und ich sehe das Verhalten dort überhaupt nicht. Ich habe einen Tab für einen ganzen Tag minimiert gelassen und er wurde kein einziges Mal getrennt. Ich habe daher versucht, zum iMac zurückzukehren, alle Internet-Plugins zu entfernen und alle Erweiterungen zu deaktivieren, aber ich habe dieses Verhalten trotzdem gesehen.

Apple scheint keine andere Möglichkeit zu bieten, Safari vollständig neu zu installieren, als seine Einstellungen und bestimmte andere Dateien zu löschen. Oder die Maschine abwischen. Ein Teil von mir möchte einfach neu anfangen, aber der Entwickler in mir würde es hassen, nicht zu wissen, was die Ursache ist.

Eigentlich zu Ihrem Punkt bezüglich der exponentiellen erneuten Verbindung: Sicherlich würde die erste erneute Verbindung, wie Sie sagen, etwa 500 ms nach dem Trennen der Verbindung erfolgen. Warum sollte der Server sie dann ignorieren? Es muss etwas geben, das verhindert, dass die erneute Verbindung ausgelöst wird.

Es ist ein bisschen komisch, denn wenn ich ein socket.connect() in das Disconnect-Ereignis stecke, wird die Verbindung wieder einwandfrei hergestellt. Es muss es alle paar Minuten tun, aber es tut es immer noch ohne Fehler. Ich bin also völlig verwirrt darüber, warum keine erneute Verbindung stattfindet! Ich werde ein bisschen mehr graben und sehen, ob ich herausfinden kann, warum.

Dies ist heutzutage ein typisches Browserverhalten, leider auch auf Desktops.

Ich glaube ich weiß was passiert. Safari ist in der Tat das Problem.

Ich denke, alle Browser begrenzen die Werte für setTimeout und setInterval auf 1000, wenn die Registerkarte nicht scharfgestellt ist. Safari - dumm - begrenzt es auf 1000 und fügt exponentiell eine Verzögerung hinzu, die dazu führt, dass jede Iteration doppelt so lange dauert wie die letzte. Aus diesem Grund wird die Verbindung unterbrochen. Die internen Zeitüberschreitungen von socket.io werden verzögert / gelöscht, was erklärt, warum keine erneuten Verbindungen hergestellt werden, wenn sie sollten.

Im Grunde genommen hat Apple beschlossen, wie gewohnt gegen den Strich zu gehen, was zu einer schlechten Benutzererfahrung führt. Sie sind heutzutage wirklich gut darin.

Ich habe nicht herausgefunden, warum es den iMac und nicht das MacBook betrifft (ich hätte das Gegenteil erwartet), aber ich werde weiter testen und sehen, ob ich den genauen Grund herausfinden kann.

@ Twistedpixel ist nicht nur Safari. Siehe http://blog.strml.net/2017/01/chrome-56-now-aggressively-throttles.html

In Primus haben wir das Problem umgangen, indem wir die Richtung der Heartbeat-Nachrichten umgekehrt haben (https://github.com/primus/primus/pull/534).

@lpinca Die ganze Zeit, als ich versuchte, dieses Problem herauszufinden, habe ich mich

@twistedpixel Mein Punkt ist, dass das gleiche wahrscheinlich in Engine.IO gemacht werden kann, so dass keine Migration zu Primus erforderlich ist.

FWIW, Safari Tech Preview scheint von der zusätzlichen Drosselung nicht betroffen zu sein. Vielleicht hat Apple ihre Entscheidung rückgängig gemacht. Es drosselt immer noch auf 1000 ms, scheint aber nichts weiter hinzuzufügen.

Ich habe das gleiche Problem auf iOS 12 Safari. Wenn ich meine Safari wieder öffne, ist die Websocket-Verbindung unterbrochen. Gibt es eine saubere Problemumgehung, um den Socket am Leben zu erhalten?

AFAIK iOS Safari unterbricht bestimmte Prozesse, wenn Safari im Hintergrund ausgeführt wird (um einen Batterieverbrauch zu vermeiden), und Websocket-Verbindungen sind mit ziemlicher Sicherheit ein solcher Prozess. Es ist unwahrscheinlich, dass Sie auf mobilen Geräten eine Problemumgehung finden.

IN ORDNUNG. Aber ich kann mich trotzdem wieder verbinden, wenn ich einen Ereignis-Listener wie onwindowfocus oder so hinzufüge?

Hat jemand eine Problemumgehung implementiert? Wir sind daran interessiert, Optionen zu prüfen und uns zu fragen, ob andere bereits experimentieren

Anstatt Fokusereignisse zu verwenden, müssen Sie die Seitensichtbarkeits-API verwenden , um zu erkennen, wann ein Fenster für mobile Apps im Hintergrund angezeigt wurde.

Ich bin auf das Problem mit Azure SignalR gestoßen, und dank des Vorschlags von @techpeace , der derzeit die Page Visibility API verwendet, um die Verbindung beim

Lösungen

Ich habe mehrere Stunden lang mit allen drei Browsern getestet und dabei die Werte pingTimeout & pingInterval geändert. Was ich als Lösungen gefunden habe:

  1. Festlegen von pingTimeout > = 30000 ms

    • oder -

  2. Festlegen von pingInterval <= 10000 ms

Ich glaube, die beste Lösung ist es, pingTimeout = 30000 zu ändern. Der Standardwert von pingInterval ist 25000 ms, und das Erhöhen der Häufigkeit, mit der der Server die Clients alle 10 Sekunden anpingt, kann für _at scale_-Projekte zu gesprächig sein.

Ich denke, das liegt daran, dass die aktuelle Version von socket.io auf dem Client auf setTimeout basiert, was möglicherweise nicht so zuverlässig ist wie erwartet.

Wir werden dies in die Version 3 aufnehmen, da es sich um eine bahnbrechende Änderung handelt.

Siehe auch: https://github.com/primus/primus/issues/348

@darrachequesne Ich

Gibt es ein Update zu diesem Fehler in Socket Io?

Wenn der Benutzer in meiner App versucht, eine Datei über seinen mobilen Browser hochzuladen, und wenn das Dialogfeld zum Hochladen geöffnet wird, werden sie von Socket Io getrennt, wenn die Auswahl einer Datei mindestens 15 Sekunden dauert.

Wenn sie nach 15 Sekunden zu einer anderen Seite oder Registerkarte wechseln, werden sie durch Socket Io wieder getrennt. Gibt es eine Möglichkeit, dies zu beheben und Socket Io am Leben zu erhalten / zu verbinden, auch wenn der Benutzer nicht auf Seite / Dokument fokussiert ist?

@ Darrachequesne

Ich habe dieses Problem mit der Sichtbarkeits-API behoben.

Hauptproblem mit Safari für mich - es hat keine Zeit, den Socket auf visible.hidden === true zu schließen. Sie müssen den Websocket also schließen, nachdem das Gerät entsperrt wurde, und ihn erneut starten.

@ JustFly1984 Hast du einen Beispielcode

Dies geschieht nun auch mit MacOS Safari, FYI.

@calendee @anilanar Wir verwenden nicht sockets.io, sondern nur reine Websockets, und wir verwenden auch React.js, daher ist der Code ziemlich komplex. Die Hauptidee, dass wir zwei <ContextProvider /> für jede API haben, ist die Sichtbarkeit oben, die Websockets unten und die Websockets, die den Kontext der Sichtbarkeit verwenden.

Vielen Dank, dass Sie sich bei mir gemeldet haben. JustFly1984. Letztendlich brauchte ich die Sichtbarkeits-API nicht. Ich muss nur Timeouts hinzufügen. Nachdem ich dies getan hatte, hatte ich keine Verbindungsprobleme mehr mit iOS Safari.

// Establish a Socket.io connection
// Initialize our Feathers client application through Socket.io
// with hooks and authentication.
client.configure(feathers.socketio(socket), {
  timeout: 2000,
});
// Use localStorage to store our login token
client.configure(feathers.authentication(), {
  timeout: 2000,
});
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen