Начиная с https://github.com/TheThingsNetwork/lorawan-stack/pull/2565 потоки событий в блоке консоли после щелчка мышью в консоли.
В какой-то момент консоль продолжает загружаться. Похоже, это вызвано «слишком большим количеством открытых подключений», потому что запросы /api/v3/events
не закрыты.
Консоль должна оставаться отзывчивой.
Сборка на основе текущей master
ветки 3df51cd750f57b37c3acffc28b417441babdbf30 (не обращайте внимания на 3.8.5, отображаемую консолью)
Я подозреваю, что это вызвано тем, что заголовки пишутся только прямо перед первым сообщением в потоке. Если сообщения нет, значит нет заголовка и браузер продолжает ждать.
Итак, чтобы исследовать, я предлагаю:
Попробуйте шаги воспроизведения
Консоль Firefox загружается вечно, если есть 6 открытых вкладок - если, например, обновляется одна из рабочих вкладок - одна из вкладок загрузки разблокируется, но иногда кажется, что это не удается.
Во всяком случае, я пробовал отправлять сообщения начала / окончания, но это ничего не изменило - оно все равно зависает после 6 вкладок.
Примечание: все вкладки предназначены для просмотра данных шлюза (2 разных)
@kschiffer есть идеи?
Консоль Firefox загружается вечно, если есть 6 открытых вкладок - если, например, обновляется одна из рабочих вкладок - одна из вкладок загрузки разблокируется, но иногда кажется, что это не удается.
Это ожидается, и ограничение на отключение потоков событий без использования HTTP / 2 :
Когда SSE не используется через HTTP / 2 , у него есть ограничение на максимальное количество открытых подключений, что может быть особенно болезненным при открытии различных вкладок, поскольку ограничение составляет _ на браузер_ и установлено очень маленькое число (6). Проблема была помечена как «Не исправить» в Chrome и Firefox . Этот предел установлен для браузера + домена, поэтому это означает, что вы можете открыть 6 подключений SSE на всех вкладках к
www.example1.com
и еще 6 подключений SSE кwww.example2.com.
(из Stackoverflow ). При использовании HTTP / 2 максимальное количество одновременных _HTTP-потоков_ согласовывается между сервером и клиентом (по умолчанию 100).
У меня проблемы с воспроизведением исходной проблемы, так как у меня есть доступ только к двум подключенным шлюзам в промежуточной среде.
Я подозреваю, что это вызвано тем, что заголовки пишутся только прямо перед первым сообщением в потоке. Если сообщения нет, значит нет заголовка и браузер продолжает ждать.
Я могу это подтвердить. Запросы будут остановлены, если они не получат заголовок ответа. После открытия шести таких подключений все последующие XHR также остановятся.
До # 2565 это не было проблемой, поскольку поток событий всегда немедленно отправлял «сообщение о запуске потока», что приводило к отправке заголовков.
Таким образом, я не считаю это проблемой внешнего интерфейса. Единственное, что имеет смысл изменить во внешнем интерфейсе, - это убедиться, что застрявшие потоковые соединения прерываются через определенное время.
Таким образом, проблема возникает, когда потоки событий не отправляют никаких данных. XHR, выполняющий соединение с потоком событий, разрешится только после получения первого сообщения, в противном случае он зависнет в состоянии
pending
. После открытия 6 из этих подключений все остальные также будут зависать, поскольку было достигнуто максимальное количество одновременных TCP-подключений. Таким образом, похоже, что XHR ожидает от сервера какого-то подтверждения, что поток установлен.До # 2565 это не было проблемой, поскольку поток событий всегда отправлял «сообщение о запуске потока».
В настоящее время я пытаюсь выяснить, можно ли и как это исправить на стороне интерфейса.
По моему опыту, отправка «начального сообщения» не помогает в решении этой проблемы. Пожалуйста, попробуйте сами со следующей разницей:
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 {
Вот видео:
https://youtu.be/0Ir0lakV-Mc
Я вижу разницу.
На master
БЕЗ разницы:
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
На master
С разн.
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
Мы должны дифференцировать эту проблему:
Чтобы смягчить 2, необходимо немедленно отправить заголовок ответа.
Что касается консоли, здесь следует отметить одну вещь: мы также должны рассмотреть возможность отмены ожидающих запросов. В настоящее время запросы могут быть отменены только после установления потокового соединения.
@kschiffer, не могли бы вы дать шаги, чтобы воспроизвести проблему в 2.?
Я постоянно обновляю вкладку данных одного шлюза и не испытываю зависаний с последней версией master
(без патча)
Самый простой способ - создать совершенно новый и неподключенный шлюз, поскольку он не будет отправлять никаких сообщений. Затем перейдите на страницу обзора и вернитесь к списку шлюзов шесть раз.
Это проблема не только для событий шлюза, но и для всех потоков событий.
Отмена назначения меня, поскольку проблема не в консоли.
Закрыл # 2989
Временное решение было представлено на https://github.com/TheThingsNetwork/lorawan-stack/pull/2989 - более надежного решения пока не найдено.
Так что это либо что-то в наших зависимостях (grpc-gateway не сбрасывает заголовки должным образом), либо в нашем общем коде (возможно, какое-то промежуточное ПО grpc или http не сбрасывает заголовки).
Удаление ярлыка bug
потому что в настоящее время он не влияет на наших пользователей.
Пожалуйста, откройте новую проблему, если есть что-то, что нужно решить.
Самый полезный комментарий
Так что это либо что-то в наших зависимостях (grpc-gateway не сбрасывает заголовки должным образом), либо в нашем общем коде (возможно, какое-то промежуточное ПО grpc или http не сбрасывает заголовки).
Удаление ярлыка
bug
потому что в настоящее время он не влияет на наших пользователей.