Server Sent Events (SSE) jako konkurencja do technologii WebSocket

Długo zbierałem się omówieniem tego tematu, głównie z powodu wciąż trwających przeze mnie testów technologi SSE. Pomimo, że w dalszym ciągu nie mam w pełni wyrobionego zdania to postanowiłem coś napisać i spróbować porównać obie technologie wymiany informacji między klientem a serwerem. Temat jest obszerny, mamy wiele sposobów na wykorzystanie tych rozwiązań, podobnie jak narzędzi, bibliotek czy już nawet frameworków, nie mówiąc o różnych edge casach im towarzyszących. Dlatego też tym wpisem chciałbym jedynie nakreślić ogólną problematykę i przedstawić mój przykład implementacji SSE w miejsce dotychczas używania WebSocket, zapraszam do lektury.

Co skłoniło mnie do porzucenia websocketów? Odpowiedź jest prosta, ich problematyczna natura. Niestabilność połączenia, wiele różnych sposobów na tak zwany „handshake”, niekompatybilność bibliotek czy samych przeglądarek. Momentami myślałem, że strzelam z armaty do muchy, zatem pomysł by uprościć komunikacje,uczynić ją jednokierunkową i wykorzystać ustrukturyzowane API EventSource wydaje się całkiem obiecujący.

Moje testy przeprowadziłem wspomagając się otwarto źródłowym oprogramowaniem Mercure. Stanowi on gotowe rozwiązanie do obsługi komunikatów, które serwer może wysłać do przeglądarki. Serwer łączy się zatem z Mercure Hub’em – aplikacją, która kolejkuje komunikaty od serwera i wysyła je do odpowiednich subskrybentów (klientów) danego tematu. Tworząc komunikat – wiadomość, określamy z jakim tematem jest ona związana. Co istotne, Mercure Hub potrafi buforować wiadomości i odesłać je do subskrybenta w kolejności nadania nawet jeśli klient połączy się po jakimś dłuższym czasie od pierwotnego czasu nadania wiadomości. Cała komunikacja może być szyfrowana i wymagać uwierzytelnienia. Możemy też określić jacy subskrybenci i nadawcy mają dostęp do danych tematów. Ciekawe, że Mercure dostarcza standard do implementacji hub’a, zatem pojawiły się implementacje nawet na procesory wykorzystane w Raspberry czy Qnap. By było jeszcze bardziej słodko Symfony posiada bundle integrujący się z naszym hubem. Ułatwia to nam publikowanie wiadomości i ich ewentualne debugowanie, a wszystko to przy minimalnej wymaganej konfiguracji. Większe wyzwanie stanowi część kliencka, jeśli planujemy uwierzytelnianie to musimy zrezygnować z wbudowanego w przeglądarki api Event Source i wykorzystać EventSourcePolyfill (co z kolei pozbawi nas wygodnego wbudowanego w przeglądarce debuggera komunikatów). Pamiętajmy, że technologia SSE jest komunikacją w jedną stronę, zatem po odebraniu wiadomości z serwera, gdy zajdzie konieczność otrzymania dodatkowych danych to musimy wykonać do serwera reguest XHR.

Projektem dla którego zdecydowałem się podmienić WebSockety na SSE stanowi prosta aplikacja do kasowania duplikatów zdjęć, w której pomocne jest monitorować zadania skanowania danych katalogów. Owe zadania są wykonywane równolegle przez workery, więc śledzenie ich pracy, aby miało jakiś sens, musi odbywać się w czasie rzeczywistym. Komunikat jaki serwer przesyła to informacja, jakie zadanie zmieniło swój status i w jakim procencie jest ono gotowe. Klient nie musi wysyłać do serwera dodatkowych żądań, oprócz wysłania zadania do kolejki czy gotowość na nasłuchiwanie tych statusów. W tej roli SSE wypada znakomicie. Co może stanowić problem? W moim przypadku ograniczenia w rozmiarze wiadomości, choć można przesłać cały obiekt zserializowany do formatu JSON to należy mieć na uwadzę parametry pracy danego Hub serwera. Warte zastanowienia jest czy wiadomość wysłana przez SSE powinna się ograniczać jedynie do typów prostych? Ja postanowiłem wysyłać jedynie identyfikatory zmienionych zadań, następnie klient wykonuje żądanie o dodatkowe informacje do serwera wówczas.

Jakie wady można zaobserwować po wdrożeniu SSE? Ograniczenia w formacie przesyłanych danych (tylko UTF-8), w liczbie dozwolonych równoległych połączeń (zależy od przeglądarki) czy jednokierunkowość komunikacji, ale jak dla mnie to ostatnie jest zaletą. Nie mniej w roli wysyłania powiadomień do klienta, to rozwiązanie sprawdza się znakomicie.