Steven
Steven5 мин четене

Транскрипция на живо, когато защитната стена блокира WebSocket-ите

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

Транскрипция
Мрежи
Инженерство
GeekBye издания
Транскрипция на живо, когато защитната стена блокира WebSocket-ите

Има един конкретен, влудяващ начин, по който транскрипцията в реално време се проваля в корпоративна мрежа. Wi-Fi-ят ти е наред. HTTPS работи — можеш да заредиш всеки сайт. Но транскрипцията на живо просто... не тръгва, и нищо не ти казва защо.

Виновникът е клас корпоративни proxy-та, които разрешават обикновения HTTPS трафик, но блокират WebSocket upgrade-а — handshake-а, който превръща една HTTPS връзка в постоянния, двупосочен канал, от който транскрипцията в реално време има нужда. За proxy-то WebSocket изглежда като немониториран тунел навън от мрежата, така че го убива. За теб транскрипцията е безшумно счупена.

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

Защо fallback, а не просто retry

Вече се справяме с нестабилни мрежи. Ако връзката ти падне по средата на сесия, GeekBye се свързва отново с backoff и буферира аудиото ти, така че нищо да не се губи — това е отделна функция, разгледана в защо твоят AI notetaker спира при лош Wi-Fi.

Но блокиран WebSocket не е нестабилна връзка. Повторното опитване на същия WebSocket срещу proxy, който отказва WebSocket-ите, се проваля по същия начин всеки път, завинаги. Единственото решение е различен транспорт — такъв, който изглежда като обикновения HTTPS, който proxy-то вече разрешава.

Затова v2.0.8 преминава към чист HTTPS транспорт през същия автентикиран endpoint:

  • Надолу (транскрипциите, идващи обратно към теб): server-sent events — дълготраен HTTPS отговор, който proxy-то вижда като обикновено стриймвано изтегляне.
  • Нагоре (аудиото ти, което излиза): групирани POST заявки, всяка носеща парче аудио с пореден номер, така че сървърът да може да ги сглоби в правилния ред, дори ако мрежата ги пренареди.

Никакъв постоянен socket, нищо, което да изглежда като тунел — само HTTPS заявки и отговори. Ако proxy ти позволява да ползваш сайт, позволява и това.

Бъгът, който щеше да пусне мъртва функция

Ето частта, която си струва да прочетеш. Fallback-ът трябва да се задейства, когато WebSocket връзката изчерпи опитите си със сигнатура на блокиран транспорт — всеки опит се проваля на upgrade-а, никакъв auth или quota проблем, поне един отказ с форма на 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; истинска auth 403 не трябва.

Останалата част от каляването следваше същата параноична линия: timeout на всеки POST нагоре, така че proxy, което приема заявка, но никога не отговаря, да не може да задръсти аудио потока, и гаранция, че истински проблем със sign-in никога не може да бъде безшумно замаскиран от механизма за fallback.

Тествахме го срещу реален враждебен proxy

Функция, чиято цялостна цел е оцеляване във враждебни мрежи, не може да бъде валидирана само с unit тестове — unit тестовете нямат proxy-та. Преди да я активираме, прекарахме реалното приложение през локален reverse proxy, конфигуриран да прави точно това, което правят корпоративните proxy-та: препраща HTTPS, отхвърля WebSocket upgrade-ите с 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-а зад флаг и валидиран. За работата по надеждността, до която стои, виж защо твоят AI notetaker спира при лош Wi-Fi, а за съседните издания в тази серия — защо твоят AI notetaker спира записа по средата на срещата (v2.0.9) и защо AI транскрипцията греши техническите термини (v2.0.11).

Свързани статии

Денят, в който приложението ни направи DDoS само на себе си
Steven
Steven5 мин четене

Денят, в който приложението ни направи DDoS само на себе си

Backlog от чакащи качвания, освободен наведнъж при стартиране, превърна всеки GeekBye клиент в малка denial-of-service атака срещу собствените ни сървъри. Фиксът — и стълбата за connection-liveness, която ни принуди да построим — е едно от най-полезните неща, на които ни научи v2.

Надеждност
Мрежи
Инженерство
Защо AI транскрипцията греши техническите термини (и как го поправихме)
Steven
Steven6 мин четене

Защо AI транскрипцията греши техническите термини (и как го поправихме)

Сесия на живо чу "what is the pointer in C++" като "what is the point in life". Ето криминалистичната следа от този транскрипт до GeekBye v2.0.11 — keyterm biasing, състезание по време, което прекъсваше връзката, и денят, в който собственият ни фикс даде обратен ефект.

Транскрипция
Надеждност
Инженерство
Защо записът на екрана хваща грешния монитор (и как го поправихме)
Steven
Steven4 мин четене

Защо записът на екрана хваща грешния монитор (и как го поправихме)

При настройка с два монитора GeekBye записваше и правеше екранни снимки на основния дисплей, независимо на кой екран работиш. Фиксът беше една малка функция — но първата ѝ версия беше грешна и code review хвана защо.

Запис на екран
Multi-Display
Инженерство