Steven
Steven4 хв читання

Транскрипція в реальному часі, коли файрвол блокує WebSocket

Корпоративні мережі обожнюють пропускати HTTPS і тихцем убивати upgrade до WebSocket. Це непомітно ламає транскрипцію в реальному часі. GeekBye v2.0.8 автоматично переходить на чисто-HTTPS транспорт — а його випуск викрив баг, який зробив би всю функцію непотрібною.

Транскрипція
Мережі
Інженерія
Релізи GeekBye
Транскрипція в реальному часі, коли файрвол блокує WebSocket

Є один конкретний, до сказу дратівливий спосіб, яким транскрипція в реальному часі відмовляє в корпоративній мережі. Ваш Wi-Fi у порядку. HTTPS працює — ви можете відкрити будь-який сайт. Але транскрипція наживо просто... не запускається, і ніщо не каже вам чому.

Винуватець — клас корпоративного proxy, яке пропускає звичайний HTTPS-трафік, але блокує upgrade до WebSocket — рукостискання, що перетворює HTTPS-з’єднання на постійний двосторонній канал, який потрібен транскрипції в реальному часі. Для proxy WebSocket виглядає як немоніторований тунель назовні з мережі, тож воно його вбиває. Для вас транскрипція непомітно зламана.

GeekBye v2.0.8 додав автоматичний fallback саме на цей випадок — і його створення викрило баг, через який уся функція не робила б нічого.

Чому fallback, а не просто повтор

Ми вже даємо раду нестабільним мережам. Якщо ваше з’єднання обривається посеред сесії, GeekBye перепідключається з backoff і буферизує ваше аудіо, щоб нічого не пропало, — це окрема функція, описана в чому ваш ШІ-нотатник зупиняється на поганому Wi-Fi.

Але заблокований WebSocket — це не нестабільне з’єднання. Повтор того самого WebSocket проти proxy, яке відмовляє WebSocket’ам, відмовляє однаково щоразу, вічно. Єдине виправлення — інший транспорт, який виглядає як простий HTTPS, що proxy вже пропускає.

Тож v2.0.8 переходить на чисто-HTTPS транспорт через той самий автентифікований endpoint:

  • Вниз (транскрипти, що повертаються до вас): server-sent events — довгоживуча HTTPS-відповідь, яку proxy бачить як звичайне потокове завантаження.
  • Вгору (ваше аудіо, що йде назовні): батчеві POST-запити, кожен несе фрагмент аудіо з порядковим номером, щоб сервер міг зібрати їх по порядку, навіть якщо мережа їх переставить.

Жодного постійного сокета, нічого, що виглядає як тунель, — лише HTTPS-запити й відповіді. Якщо proxy дозволяє вам користуватися сайтом, воно дозволяє й це.

Баг, який випустив би мертву функцію

Ось частина, заради якої варто читати. Fallback має спрацьовувати, коли WebSocket-з’єднання вичерпує свої спроби із сигнатурою заблокованого транспорту — кожна спроба відмовляє на upgrade, жодних проблем з auth чи лімітом, щонайменше одне відхилення у формі proxy. Proxy, що блокує WebSocket, зазвичай відповідає на upgrade HTTP 403 Forbidden або 407.

Проблема: у нашому коді з’єднання вже було правило, що 403 означає фатальну помилку автентифікації — зупинись, покажи її користувачеві, не повторюй. Що правильно майже всюди. Але це означало, що 403 від блокуючого proxy — рівно той сигнал, який мав запустити fallback — натомість викидалося як фатальна помилка перш ніж логіка fallback узагалі могла запуститися. Лише сирий обрив з’єднання (закриття 1006) провалювався далі до fallback. Тож функція працювала б для рідкісного випадку і тихцем відмовляла б для своєї справжньої головної цілі: корпоративного proxy.

Ми спіймали це під час загартування релізу, а не в продакшені. Виправлення: 403/407 на upgrade-етапі WebSocket тепер трактується як відновлюване, щоб цикл з’єднання міг вичерпатися у fallback, — тоді як справжня відмова автентифікації (яка приходить інакше, після успішного upgrade) досі відмовляє швидко, рівно як раніше. Регресійний тест тепер закріплює цю різницю: 403 від заблокованого proxy має піти у fallback; справжнє 403 auth — ні.

Решта загартування пішла тією самою параноїдальною лінією: тайм-аут на кожному вихідному POST, щоб proxy, яке приймає запит, але ніколи не відповідає, не могло застопорити аудіопотік, і гарантія, що справжня проблема входу ніколи не може бути тихцем замаскована машинерією fallback.

Ми протестували це проти справжнього ворожого proxy

Функцію, увесь сенс якої — виживати у ворожих мережах, не можна перевірити самими юніт-тестами — у юніт-тестів немає proxy. Перш ніж увімкнути її, ми прогнали реальний застосунок через локальне reverse proxy, налаштоване робити рівно те, що роблять корпоративні proxy: пропускати HTTPS, відхиляти upgrade’и WebSocket із 403.

Слід у логах — це чек: чотири заблоковані спроби WebSocket, розпізнана сигнатура вичерпання, автоматичне перемикання на HTTPS-транспорт, а потім здорова 96-секундна сесія транскрипції по чистому HTTPS — 66 сегментів транскрипту, нуль втрат. Failover працює, бо ми бачили, як він перемикається.

Три переносні уроки

  1. «Працює на нестабільному Wi-Fi» і «працює за ворожим proxy» — це різні гарантії. Одній потрібне перепідключення; іншій потрібен інший транспорт. Змішувати їх — значить лишити цілу популяцію корпоративних користувачів тихцем зламаною.
  2. Ваша класифікація помилок може сховати вашу ж функцію від неї самої. Правило, вірне у 99% випадків (403 = фатальний auth), було рівно хибним для того 1%, заради якого ця функція й існувала. Коли ви додаєте fallback, перевірте, чи умова спрацювання взагалі може дійти до fallback.
  3. Тестуйте супротивника, а не лише щасливий шлях. Єдиний чесний тест «виживає proxy, що блокує WebSocket» — це proxy, що блокує WebSocket. Ми його побудували.

GeekBye v2.0.8 випустив HTTPS-fallback за прапорцем і перевіреним. Про сусідню з ним роботу над надійністю дивіться чому ваш ШІ-нотатник зупиняється на поганому Wi-Fi, а про сусідні релізи цієї серії — чому ваш ШІ-нотатник зупиняє запис посеред зустрічі (v2.0.9) і чому ШІ-транскрипція перекручує технічні терміни (v2.0.11).

Схожі статті

День, коли наш застосунок влаштував DDoS самому собі
Steven
Steven5 хв читання

День, коли наш застосунок влаштував DDoS самому собі

Черга відкладених завантажень, випущена вся разом при запуску, перетворила кожен клієнт GeekBye на маленьку атаку denial-of-service на наші власні сервери. Виправлення — і драбина liveness з’єднання, яку воно змусило нас побудувати — одна з найкорисніших речей, яких навчив нас v2.

Надійність
Мережі
Інженерія
Чому ШІ-транскрипція перекручує технічні терміни (і як ми це виправили)
Steven
Steven6 хв читання

Чому ШІ-транскрипція перекручує технічні терміни (і як ми це виправили)

Жива сесія почула «what is the pointer in C++» як «what is the point in life». Ось слід розслідування від того транскрипту до GeekBye v2.0.11 — keyterm biasing, гонка, що обривала з'єднання, і день, коли наш власний фікс обернувся проти нас.

Транскрипція
Надійність
Інженерія
Чому запис екрана захоплює не той монітор (і як ми це виправили)
Steven
Steven4 хв читання

Чому запис екрана захоплює не той монітор (і як ми це виправили)

На конфігурації з двома моніторами GeekBye записував і робив скриншоти з основного дисплея незалежно від того, на якому екрані ви працювали. Фікс умістився в одну невелику функцію — але перша її версія була хибною, і код-рев’ю впіймало чому.

Запис екрана
Кілька дисплеїв
Інженерія