Požadavek přichází do zadání téměř vždy ve stejné podobě: „chceme, aby se to aktualizovalo živě, bez obnovování stránky“. Zní to jako detail — jde přece jen o to, aby číslo na obrazovce nezaostávalo za realitou. Ve skutečnosti je to jedno z rozhodnutí, která nejvíc mění architekturu aplikace, náklady na provoz i to, co všechno musí tým po spuštění sledovat.
Rozdíl je principiální. Běžná webová aplikace odpovídá na otázky: přijde požadavek, vrátí se odpověď, spojení se zavře a server na klienta zapomene. Real-time webová aplikace si musí s každým otevřeným prohlížečem udržovat vztah — vědět, kdo je připojen, co ho zajímá, co mu už poslala a co poslat nestihla. Tento článek je o tom, jak k takovému požadavku přistoupit střízlivě: kdy dává smysl, jaké možnosti existují, co každá z nich stojí a jaké pasti čekají ve chvíli, kdy spojení spadne nebo dva lidé upraví stejný záznam.
Potřebujete opravdu real-time, nebo jen čerstvější data?
První otázka není technická, ale produktová: co špatného se stane, když uživatel uvidí údaj starý patnáct sekund? U velké části firemních aplikací je odpověď „nic“. Vedoucí, který se dívá na přehled, nepotřebuje, aby se čísla měnila přímo před očima — potřebuje, aby nebyla včerejší. Dispečer přidělující vozidla nebo dva lidé ve stejném formuláři jsou jiný případ; tam zpoždění přímo způsobuje kolize a duplicitní práci.
Pomáhá rozdělit obrazovky do tří skupin:
- Skutečný real-time (do sekundy). Rozhodnutí se dělá okamžitě a několik lidí pracuje se stejným objektem: chat, souběžná editace, dispečink, monitoring s alarmy.
- Čerstvá data (jednotky až desítky sekund). Seznamy objednávek, stavy úkolů, provozní přehledy. Uživatel toleruje krátké zpoždění, jen nechce klikat na obnovit.
- Dávkové zobrazení. Reporty, uzávěrky, přehledy za období. Tady je „živost“ spíš na škodu — čísla, která se mění během čtení, se špatně interpretují a ještě hůř porovnávají.
Druhá skupina je v praxi nejpočetnější a téměř vždy jí stačí periodické načítání. Klient se každých pár sekund zeptá serveru, jestli je něco nového; s podmíněnými požadavky (ETag, If-Modified-Since) je odpověď většinou prázdná a levná. Když je záložka na pozadí, interval se prodlouží nebo zastaví. Nevzniká žádná nová infrastruktura, projde to přes každou firemní proxy, chyby se ladí běžnými nástroji a opakování požadavku je zabudované v samotném principu. Pokud je cílem hlavně to, aby vedení vidělo aktuální čísla bez ručního exportu, téma rozebíráme podrobněji v textu o reportech pro vedení firmy v reálném čase.
Polling, SSE a WebSockety: co každá volba stojí
Pokud jste prošli předchozím filtrem a real-time skutečně potřebujete, výběr přenosové vrstvy je hlavně rozhodnutí o provozu, ne o rychlosti. Všechny varianty umí doručit data dost rychle; liší se tím, co po vás pak chtějí každý den.
| Přístup | Tok dat | Typická latence | Provozní náročnost | Kdy je dobrá volba |
|---|---|---|---|---|
| Periodický polling | klient se ptá | interval (např. 5–30 s) | nejnižší | přehledy, seznamy, stavy úkolů |
| Long polling | klient se ptá, server drží | téměř okamžitě | střední | když potřebujete rychlost, ale ne obousměrnost |
| Server-sent events (SSE) | server → klient | téměř okamžitě | střední | notifikace, živé grafy, streamované odpovědi |
| WebSockety | obousměrně | nejnižší | nejvyšší | chat, souběžná editace, hry, dispečink |
| Hostovaná real-time služba | podle poskytovatele | téměř okamžitě | nízká vývojově, vyšší finančně | malý tým, který nechce provozovat vlastní vrstvu |
Server-sent events jsou v projektech, které vídáme, nejčastěji podceňovanou volbou. Jde o obyčejné HTTP spojení, které server nechá otevřené a posílá do něj řádky textu. Automatické obnovení spojení i číslování zpráv jsou součástí standardu, funguje to přes běžnou HTTP infrastrukturu a na straně serveru nepřibývá samostatný protokol. Pokud potřebujete jen směr „ze serveru k uživateli“ — a u notifikací a živých grafů je to přesně ten případ — WebSockety jsou často zbytečně těžké řešení.
WebSockety zvolte tehdy, když klient reálně posílá hodně zpráv zpět a záleží na pořadí a latenci obou směrů. Cenou je vlastní protokol nad spojením, vlastní autentizace a autorizace pro každou zprávu a nutnost řešit to, co HTTP řeší za vás. Rozdíl mezi technologiemi je nakonec menší než rozdíl mezi „máme to zapnuté“ a „umíme to provozovat“, což je téma, kterému se věnujeme i při návrhu webových aplikací na míru.
Každé otevřené spojení je malý kus stavu, který musíte někde držet, platit za něj a jednou ho i korektně zavřít.
Stav, který se rozpadne: proč real-time UI potřebuje rekonciliaci
Na tomhle bodě padne většina prvních implementací. Vývojář otestuje funkci na kancelářské wi-fi, vidí, že zprávy chodí, a považuje věc za hotovou. Realita je ale jiná: mobilní síť se přepne, notebook si zdřímne, firemní proxy zabije nečinné spojení po minutě, nasazení nové verze odpojí naráz všechny. Uživatel přitom nedostane žádné varování — obrazovka jednoduše přestane žít a tváří se, že je aktuální.
Proto platí jednoduché pravidlo: tok zpráv není zdroj pravdy, je to jen optimalizace. Zdrojem pravdy zůstává server a rozhraní musí mít cestu, jak se s ním kdykoli srovnat. Prakticky to znamená tři věci:
- Detekce. Pravidelný heartbeat oběma směry a viditelný indikátor stavu spojení. Když uživatel vidí „obnovujeme spojení“, neudělá rozhodnutí nad mrtvými daty.
- Obnova. Po opětovném připojení buď dotáhněte chybějící události od posledního známého pořadového čísla, nebo — což je jednodušší a pro většinu aplikací zcela dostačující — načtěte celý stav obrazovky znovu a stream použijte až od té chvíle.
- Idempotence. Počítejte s tím, že zpráva přijde dvakrát nebo v jiném pořadí. Zpracování události musí být bezpečné opakovat, jinak se v seznamu objeví duplicity, které nikdo neumí vysvětlit.
Optimistické změny a konflikty při souběžné editaci
Optimistické UI — tedy zobrazení změny okamžitě, ještě před potvrzením serveru — je to, co dává aplikaci pocit svižnosti. Zároveň je to nejčastější zdroj tichých nekonzistencí. Každá optimistická změna potřebuje tři stavy: čekající, potvrzená, zamítnutá. Zamítnutí musí umět změnu vrátit zpět a srozumitelně to oznámit, ne ji jen tiše přepsat.
Při souběžné editaci se rozhodujete mezi třemi režimy. Nejjednodušší je zámek na záznamu — dokud s ním někdo pracuje, ostatní vidí jen pro čtení; je to nepohodlné, ale předvídatelné. Druhou možností je verzování na úrovni záznamu: klient posílá verzi, kterou viděl, a server odmítne zápis nad novější verzí. Třetí, nejdražší možnost je slučování na úrovni polí nebo datové struktury navržené pro automatické slučování, které potřebujete prakticky jen u společného psaní textu.
Škálování real-time vrstvy
Dokud běží jeden aplikační server, je všechno jednoduché: událost vznikne a server ji pošle svým připojeným klientům. Ve chvíli, kdy přidáte druhý server, to přestane fungovat — uživatel připojený na server A se nedozví o události, která vznikla na serveru B. Řešením je distribuční vrstva, přes kterou si servery události navzájem rozesílají: message broker nebo publish/subscribe kanál.
S tím souvisejí další tři věci, které je třeba vyřešit dřív než v produkci, ne potom:
- Přilepené relace a časové limity. Load balancer musí vědět, že spojení má zůstat na stejném uzlu, a jeho limit nečinnosti musí být delší než interval heartbeatu.
- Limity počtu spojení. Jedno spojení spotřebuje paměť a systémový deskriptor. Kapacita uzlu se tak neplánuje podle počtu požadavků za sekundu, ale podle počtu současně přihlášených lidí.
- Nápor po nasazení. Restart odpojí všechny naráz a všichni se naráz pokusí připojit zpět. Bez exponenciálního odstupu s náhodným rozptylem si tím aplikace složí vlastní start.
Nezapomeňte ani na autorizaci. U klasického HTTP se oprávnění ověřují při každém požadavku; u dlouho otevřeného spojení se ověří jednou při připojení a potom může člověk o přístup přijít, ale data mu chodí dál. Kontrola musí být při odeslání každé zprávy. Širšímu kontextu růstu zátěže se věnujeme v článku o škálování webové aplikace s růstem firmy.
Design notifikací: kanál, dávkování a pozornost
Technická část notifikací je jednodušší než ta produktová. Rozhodnutí, které rozhoduje o úspěchu, zní: která událost si zaslouží vyrušit člověka a která má jen tiše počkat v aplikaci.
| Kanál | Vhodný pro | Hlavní riziko |
|---|---|---|
| In-app seznam | běžné události, kontext práce | uživatel ho nemusí otevřít |
| Push do prohlížeče | časově citlivé události | povolení se ptá jednou, odmítnutí je trvalé |
| souhrny, věci na později | snadno skončí v zapomenuté složce | |
| SMS a volání | kritická selhání, pohotovost | drahé a rušivé; jen pro úzkou skupinu |
Pár zásad, které se osvědčily bez ohledu na obor: nikdy neupozorňujte člověka na jeho vlastní akci; slučujte související události do jedné zprávy s odstupem několika minut místo pěti samostatných; dejte nastavení podle typu události, ne jen jeden vypínač na všechno; a synchronizujte stav „přečteno“ mezi zařízeními, jinak uživatel řeší totéž dvakrát. Pokud uvažujete o push notifikacích bez nativní aplikace, jde prakticky o téma progresivních webových aplikací — a je třeba počítat s tím, že podpora se mezi platformami stále liší.
Provozní daň: co real-time přidá k monitoringu a testování
Real-time funkce přinášejí třídu chyb, kterou klasický monitoring nezachytí. Server odpovídá, chybovost je nula, stránka se načte rychle — a přesto polovina uživatelů vidí stará data, protože jim před hodinou spadlo spojení a nikdy se neobnovilo. Proto potřebujete měřit jiné věci: počet aktivních spojení, míru opětovných připojení, zpoždění mezi vznikem události a jejím doručením, počet nedoručených zpráv a hloubku fronty v brokeru.
Testování je podobná kapitola. Automatizované testy musí umět otevřít dvě relace naráz a ověřit, že akce v jedné se projeví ve druhé; musí umět spojení uměle přerušit a zkontrolovat, že se stav dorovnal. Zátěžový test musí simulovat tisíc současně otevřených spojení, ne tisíc požadavků za sekundu — to jsou zcela odlišné scénáře. Jak takové scénáře zapadají do celkového procesu kontroly kvality, popisujeme v textu o QA procesu před spuštěním softwaru.
Počítejte také s tím, že real-time vrstva je zdrojem nákladů, které nezmizí po předání projektu. Otevřená spojení se platí časem, ne požadavky, takže měsíční účet roste s počtem přihlášených lidí i tehdy, když nikdo nic nedělá.
Shrnutí
Real-time webová aplikace není funkce, kterou „doděláte na konci“ — je to rozhodnutí o architektuře, provozu a rozpočtu na další roky. Postup, který se osvědčil, je nudný, ale funguje: nejdřív pojmenujte konkrétní rozhodnutí, které zpoždění pokazí; pokud takové není, udělejte polling a hotovo. Pokud je, vyberte nejjednodušší vrstvu, která stačí — u směru ze serveru k uživateli jsou to obvykle server-sent events. Potom, ještě před prvním řádkem UI, navrhněte, jak se stav dorovná po výpadku, a teprve nakonec řešte optimistické změny a konflikty.
Notifikace navrhujte jako produkt, ne jako technický vedlejší produkt: méně zpráv ve správném kanálu má vždy větší hodnotu než všechno okamžitě všude. A počítejte s tím, že monitoring a testování budou stát víc než u běžné aplikace — je to daň, kterou platíte za to, že obrazovka žije.
Pokud zvažujete, jestli má ve vaší aplikaci real-time smysl a v jakém rozsahu, rádi to s vámi projdeme na konkrétních obrazovkách — ozvěte se nám a začneme tím, co se opravdu musí dít okamžitě.