Gecə saat 11:14'də bir istifadəçi Twitter'dən mesaj yazdı: "Proqramın 30 saniyə asılı qaldı, fırlanmağa davam etdi, sonra tam öldü." Developer konsolunu açanda CareerPilot AI-nin Server-Sent Events (SSE) axınında qırmızı xətlər göründü: net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK). Google Cloud Run'un proxy-si bütün axını basdırıb dağıdırdı.
CareerPilot AI, hər sorğuda altı mərhələli agentik pipeline işlədir. İstifadəçinin 20+ saniyə boş ekrana baxmasının qarşısını almaq üçün real vaxtda məntiq addımlarını birbaşa brauzerə yayımlayan SSE axını qurulmuşdu. Son mərhələdə isə 15KB həcmində böyük bir JSON payload — bacarıq çəkiləri, rol benchmarkları, resurs linkləri və 30 günlük təqvim — göndərilirdi. Problem burada başladı.
Mühəndislər əvvəlcə Express cavab buferini və sıxılma middleware-ni günahlandırdı. Həll yolu kimi hər log sətirindən sonra res.flush() çağırmağa başladılar. Bu, daha böyük fəlakətə səbəb oldu: hər bir kiçik string üçün məcburi flush, TCP paketlərinin ixtiyari sərhədlərdə parçalanmasına yol açdı. Nəticədə böyük JSON payload ortadan bölündü, klient tərəfdə JSON.parse() xətası verdi və React UI tamamilə çökdü.
Problem əslində iki ayrı infrastruktur qüvvəsinin birləşməsindən qaynaqlanırdı. Birincisi, proxy buferləməsi: Google Cloud Run'un GFE proxy-si kiçik SSE paketlərini buferdə saxlayıb kifayət qədər məlumat toplanana qədər göndərmirdi. İkincisi, TCP axınının parçalanması: 15KB-lıq payload şəbəkə səviyyəsində çoxsaylı TCP paketlərinə bölünürdü, lakin klient hər gələn parçanı tam JSON obyekti kimi qəbul edirdi.
Həll üçün həm server, həm də klient tərəfdə dəyişikliklər edildi. Serverdə X-Accel-Buffering: no başlığı əlavə olundu, no-transform direktivi ilə proxy buferləməsi bloklandı. Klient tərəfdə isə EventSource.onmessage yerinə aşağı səviyyəli ReadableStream oxuyucusu yazıldı. Bu oxuyucu gələn baytları bir buferdə toplayır, yalnız tam \n\n sərhədləri ilə ayrılmış SSE çərçivələrini emal edir, natamam parçaları isə növbəti oxu dövrü üçün buferdə saxlayır.
Yeniləmədən sonra 100 paralel istifadəçi ilə edilən yük testində pipeline tamamlama nisbəti %67'dən %99.2-yə yüksəldi, ilk logun görünmə müddəti 28 saniyədən 1.1 saniyəyə endi, JSON xətaları isə tamamilə aradan qalxdı. Müəllifin qeyd etdiyi kimi, əsas dərs budur: lokal mühitdə hər şey ideal görünür, amma proxy arxasında yayım edən streaming arxitekturalar — SSE, WebSocket, chunked transfer encoding — ilk sətirdən müdafiəli dizayn edilməlidir.


