Lorawan-stack: Ereignisstreams blockieren die Konsole, wenn Startereignisse nicht gesendet werden

Erstellt am 21. Juli 2020  ·  14Kommentare  ·  Quelle: TheThingsNetwork/lorawan-stack

Zusammenfassung

Seit https://github.com/TheThingsNetwork/lorawan-stack/pull/2565 werden die Events im Konsolenblock gestreamt, nachdem man in der Konsole herumgeklickt hat.

Schritte zum Reproduzieren

  1. Gehen Sie zu https://tti.staging1.cloud.thethings.industries/console/gateways
  2. Öffnen Sie in einer einzigen Registerkarte ein Gateway und verwenden Sie die Breadcrumbs, um zurückzugehen
  3. Wiederholen Sie dies für jedes Gateway

Was siehst du jetzt?

Irgendwann lädt die Konsole weiter. Dies scheint durch "zu viele offene Verbindungen" verursacht zu werden, da /api/v3/events Anfragen nicht geschlossen werden.

Was möchtest du stattdessen sehen?

Die Konsole sollte reaktionsschnell bleiben.

Umfeld

Build basierend auf dem aktuellen master Zweig 3df51cd750f57b37c3acffc28b417441babdbf30 (achten Sie nicht auf die 3.8.5, die von der Konsole angezeigt wird)

Wie wollen Sie dies umsetzen?

Ich vermute, dass dies dadurch verursacht wird, dass Header nur direkt vor der ersten Nachricht im Stream geschrieben werden. Wenn keine Nachricht vorhanden ist, gibt es keinen Header und der Browser wartet weiter.

Um dies zu untersuchen, schlage ich vor:

  • Überprüfen Sie, ob wir den Header richtig schreiben
  • Überprüfen Sie, ob das gRPC-Gateway den Header richtig schreibt und leert
  • Überprüfen Sie, ob das Echo/Mux-Zeug nicht stört

Wie schlagen Sie vor, dies zu testen?

Probieren Sie die Reproduktionsschritte aus

shared dependencies

Hilfreichster Kommentar

Dies ist also entweder etwas in unseren Abhängigkeiten (grpc-gateway löscht die Header nicht richtig) oder in unserem gemeinsamen Code (vielleicht löscht irgendeine grpc- oder http-Middleware die Header nicht).

Das Label bug da es derzeit keine Auswirkungen auf unsere Nutzer hat.

Alle 14 Kommentare

Auf der Firefox-Konsole wird immer geladen, wenn 6 geöffnete Registerkarten vorhanden sind - wenn zB eine der Arbeitsregisterkarten aktualisiert wird - eine der Laderegisterkarten entsperrt, aber das scheint manchmal fehlzuschlagen.

Auf jeden Fall habe ich versucht, die Start- / Endnachrichten zu senden, aber das hat nichts geändert - es hängt immer noch, nachdem es 6 Registerkarten gibt.

Hinweis: Alle Registerkarten befinden sich in der Datenansicht eines Gateways (2 verschiedene)

@kschiffer irgendwelche ideen?

Auf der Firefox-Konsole wird immer geladen, wenn 6 geöffnete Registerkarten vorhanden sind - wenn zB eine der Arbeitsregisterkarten aktualisiert wird - eine der Laderegisterkarten entsperrt, aber das scheint manchmal fehlzuschlagen.

Das wird erwartet und eine Einschränkung, die Ereignisstreams aufhebt, wenn HTTP/2 nicht verwendet wird :

Wenn es nicht über HTTP/2 verwendet wird , leidet SSE unter einer Beschränkung der maximalen Anzahl offener Verbindungen, was beim Öffnen verschiedener Registerkarten besonders schmerzhaft sein kann, da das Limit _pro Browser_ und auf eine sehr niedrige Zahl eingestellt ist (6). Das Problem wurde in Chrome und Firefox als "Wird nicht behoben" gekennzeichnet. Dieses Limit gilt pro Browser + Domain, das heißt, Sie können 6 SSE-Verbindungen über alle Registerkarten zu www.example1.com und weitere 6 SSE-Verbindungen zu www.example2.com. (von Stackoverflow )

Ich habe Probleme, das ursprüngliche Problem zu reproduzieren, da ich nur Zugriff auf zwei verbundene Gateways in der Staging-Umgebung habe.

Ich vermute, dass dies dadurch verursacht wird, dass Header nur direkt vor der ersten Nachricht im Stream geschrieben werden. Wenn keine Nachricht vorhanden ist, gibt es keinen Header und der Browser wartet weiter.

Dies kann ich bestätigen. Die Anfragen werden angehalten, wenn sie keinen Antwortheader erhalten. Nachdem sechs solcher Verbindungen geöffnet wurden, werden alle nachfolgenden XHRs ebenfalls blockiert.

Vor #2565 war dies kein Problem, da der Event-Stream immer sofort eine "Start-Stream-Nachricht" sendete, was dazu führte, dass die Header gesendet wurden.

Als solches sehe ich es nicht als Frontend-Problem. Das einzige, was am Frontend sinnvoll zu ändern wäre, wäre sicherzustellen, dass blockierte Stream-Verbindungen nach einer bestimmten Zeit beendet werden.

Das Problem tritt also auf, wenn Ereignisströme keine Daten senden. Der XHR, der die Ereignisstromverbindung durchführt, wird erst aufgelöst, nachdem die erste Nachricht empfangen wurde, andernfalls bleibt er im Zustand pending hängen. Sobald 6 dieser Verbindungen geöffnet sind, hängen auch alle anderen Verbindungen, da die maximale Anzahl gleichzeitiger TCP-Verbindungen erreicht ist. Es sieht also so aus, als ob der XHR eine Art Bestätigung vom Server erwartet, dass der Stream eingerichtet wurde.

Vor #2565 war dies kein Problem, da der Ereignisstream immer eine "Startstream-Nachricht" gesendet hat.

Ich versuche derzeit herauszufinden, ob und wie dies auf der Frontend-Seite behoben werden kann.

Nach meiner Erfahrung hilft das Senden einer "Erstnachricht" bei diesem Problem nicht. Bitte versuchen Sie es mit folgendem Diff:

diff --git a/pkg/events/grpc/grpc.go b/pkg/events/grpc/grpc.go
index 03f229ca0..5a305b5ac 100644
--- a/pkg/events/grpc/grpc.go
+++ b/pkg/events/grpc/grpc.go
@@ -119,6 +119,10 @@ func (srv *EventsServer) Stream(req *ttnpb.StreamEventsRequest, stream ttnpb.Eve
    if err := stream.SendHeader(metadata.MD{}); err != nil {
        return err
    }
+   if err := stream.Send(&ttnpb.Event{}); err != nil {
+       return err
+   }
+   defer stream.Send(&ttnpb.Event{})

    for {
        select {

Hier ist ein Video:
https://youtu.be/0Ir0lakV-Mc

Ich sehe einen Unterschied.

Auf master OHNE Diff:

htdvisser % curl -v 'http://localhost:1885/api/v3/events' --compressed -H 'Authorization: Bearer MFRWG.DVTINRZNJDORITWD64NUJRIYVIXWCKJ3Q6VYLQY.E4K63GZ3WWTZGCIFMD7XLN7A7ACA35YCQSMFCBVCTEOMATCYGG6Q' -H 'Accept: text/event-stream' -H 'Content-Type: application/json' --data-raw '{"identifiers":[{"application_ids":{"application_id":"admin-app"}}]}'
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 1885 (#0)
> POST /api/v3/events HTTP/1.1
> Host: localhost:1885
> User-Agent: curl/7.64.1
> Accept-Encoding: deflate, gzip
> Authorization: Bearer MFRWG.DVTINRZNJDORITWD64NUJRIYVIXWCKJ3Q6VYLQY.E4K63GZ3WWTZGCIFMD7XLN7A7ACA35YCQSMFCBVCTEOMATCYGG6Q
> Accept: text/event-stream
> Content-Type: application/json
> Content-Length: 68
> 
* upload completely sent off: 68 out of 68 bytes
^C

Auf master MIT dem Diff.

htdvisser % curl -v 'http://localhost:1885/api/v3/events' --compressed -H 'Authorization: Bearer MFRWG.DVTINRZNJDORITWD64NUJRIYVIXWCKJ3Q6VYLQY.E4K63GZ3WWTZGCIFMD7XLN7A7ACA35YCQSMFCBVCTEOMATCYGG6Q' -H 'Accept: text/event-stream' -H 'Content-Type: application/json' --data-raw '{"identifiers":[{"application_ids":{"application_id":"admin-app"}}]}'
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 1885 (#0)
> POST /api/v3/events HTTP/1.1
> Host: localhost:1885
> User-Agent: curl/7.64.1
> Accept-Encoding: deflate, gzip
> Authorization: Bearer MFRWG.DVTINRZNJDORITWD64NUJRIYVIXWCKJ3Q6VYLQY.E4K63GZ3WWTZGCIFMD7XLN7A7ACA35YCQSMFCBVCTEOMATCYGG6Q
> Accept: text/event-stream
> Content-Type: application/json
> Content-Length: 68
> 
* upload completely sent off: 68 out of 68 bytes
< HTTP/1.1 200 OK
< Content-Type: text/event-stream
< Referrer-Policy: strict-origin-when-cross-origin
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Request-Id: 01EDTX9RGKRGM02YZVWNB3RXJP
< X-Xss-Protection: 1; mode=block
< Date: Wed, 22 Jul 2020 09:22:32 GMT
< Transfer-Encoding: chunked
< 
{"result":{"time":"0001-01-01T00:00:00Z"}}
^C

Wir müssen dieses Problem unterscheiden:

  1. Immer wenn sechs TCP-Verbindungen gleichzeitig pro Domäne und Browser geöffnet sind, wird jede nachfolgende Anfrage hängen bleiben. Dies ist eine Browser-Einschränkung, und IMO-Möglichkeiten, damit umzugehen, sollten in einer anderen Ausgabe erörtert werden. Dieses Problem sehe ich in Ihrem Video @rvolosatovs
  2. Wenn ein Stream-Endpunkt nicht sofort einen Antwortheader sendet, wird die Anforderung angehalten (bis der Header schließlich in der ersten Nachricht gesendet wird). Dies bedeutet, dass die Konsole, obwohl sie nur eine Registerkarte verwendet, ausstehende Stream-Verbindungen sammelt, wenn sie wiederholt zu Seiten navigiert, die Stream-Verbindungen öffnen. Nachdem sechs solcher Verbindungen geöffnet wurden, hängt die Konsole aus dem gleichen Grund wie in (1).

Um 2 abzuschwächen, muss der Antwortheader sofort gesendet werden.

Was die Konsole angeht, sollten wir hier eine Sache beachten, wir sollten auch prüfen, ob wir ausstehende Anfragen stornieren. Derzeit können die Anfragen erst abgebrochen werden, wenn die Stream-Verbindung hergestellt wurde.

@kschiffer können Sie Schritte geben, um das Problem in 2 zu reproduzieren?
Ich aktualisiere ständig einen einzelnen Gateway-Daten-Tab und erlebe keine Hänger mit dem neuesten master (ohne Patch)

Der einfachste Weg besteht darin, ein völlig neues und nicht verbundenes Gateway zu erstellen, da es keine Nachrichten sendet. Navigieren Sie dann sechs Mal zu seiner Übersichtsseite und zurück zur Gateway-Liste.

Dies ist kein spezifisches Problem für Gateway-Ereignisse, sondern übrigens für alle Ereignisströme.

Die Zuweisung wird aufgehoben, da dies kein Problem ist, das von der Konsole ausgeht.

Geschlossen von #2989

Eine temporäre Lösung wurde in https://github.com/TheThingsNetwork/lorawan-stack/pull/2989 eingeführt – eine robustere Lösung muss noch gefunden werden.

Dies ist also entweder etwas in unseren Abhängigkeiten (grpc-gateway löscht die Header nicht richtig) oder in unserem gemeinsamen Code (vielleicht löscht irgendeine grpc- oder http-Middleware die Header nicht).

Das Label bug da es derzeit keine Auswirkungen auf unsere Nutzer hat.

Bitte eröffnen Sie eine neue Ausgabe, wenn noch etwas zu klären ist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

johanstokking picture johanstokking  ·  3Kommentare

bafonins picture bafonins  ·  5Kommentare

johanstokking picture johanstokking  ·  8Kommentare

ecities picture ecities  ·  5Kommentare

ZeroSum24 picture ZeroSum24  ·  3Kommentare