Websockety w Laravel bez utrzymywania serwera websocket

Laravel sprawia, że aktualizacje na żywo wyglądają na proste. Event implementuje ShouldBroadcast, routes/channels.php określa, kto może go słuchać, a Laravel Echo w przeglądarce go odbiera. Status zamówienia zmienia się na „wysłane”, a klient widzi to bez przeładowania strony.
Dokumentacja wspomina mimochodem, że coś musi utrzymywać połączenie z każdą otwartą przeglądarką. Sam Laravel odpowiada na żądania i kończy pracę, więc broadcasting zawsze potrzebuje serwera websocket obok Twojej aplikacji. Ten wpis wyjaśnia dlaczego, czego wymaga utrzymanie takiego serwera na produkcji i jak zachować Twoje eventy i Echo dokładnie takie, jakie są, gdy połączenia utrzymuje za Ciebie chmura czasu rzeczywistego.
Dlaczego Laravel potrzebuje serwera websocket
Żądanie w Laravel jest krótkie. PHP przyjmuje żądanie, Laravel się uruchamia, Twój kontroler odpowiada, a proces jest wolny dla kolejnego żądania. To dzięki temu Laravel jest szybki i łatwy w hostowaniu, i z tego samego powodu żądanie nie może pozostać otwarte godzinami, żeby wysyłać aktualizacje do jednej przeglądarki.
Dlatego broadcasting składa się z dwóch części:
- Twoja aplikacja wysyła. Gdy wywołujesz
broadcast( new OrderUpdated( $order ) ), Laravel przekazuje event broadcasterowi, który wysyła go dalej w krótkim żądaniu. PrzyShouldBroadcastdzieje się to w zadaniu z kolejki, więc wykonuje je queue worker. - Dostarcza coś innego. Serwer websocket utrzymuje otwarte połączenie z każdą przeglądarką, pyta Twoją aplikację, kto może dołączyć do każdego kanału prywatnego, i przekazuje każdy event przeglądarkom, które go słuchają.
Pierwsza część to zwykły Laravel. Druga to osobna, stale działająca usługa i to właśnie ona wymaga pracy.
Utrzymywanie własnego serwera websocket
Laravel ma serwer websocket, który możesz uruchomić samodzielnie, a inne projekty mają swoje. Uruchomienie go na laptopie zajmuje minutę. Utrzymanie go dla prawdziwych użytkowników wymaga więcej:
- Stale działającego procesu, podtrzymywanego przez menedżer procesów, restartowanego po awarii, z własnymi logami i monitorowaniem. Na hostingu współdzielonym i platformach serverless nie da się go w ogóle uruchomić.
- Portu, certyfikatu i proxy, żeby przeglądarki mogły łączyć się przez
wss://w Twojej domenie, z proxy skonfigurowanym tak, żeby przepuszczało websockety i nie zrywało długich połączeń. - Miejsca na wiele połączeń. Każda otwarta przeglądarka to otwarte połączenie, a serwer i system operacyjny muszą mieć limity ustawione na tysiące takich połączeń naraz.
- Więcej niż jednego serwera, w miarę wzrostu. Jeden serwer to jedno miejsce, w którym mogą zerwać się wszystkie połączenia. Dwa lub więcej potrzebują wspólnego kanału, zwykle Redis, żeby event wysłany do jednego dotarł do przeglądarek połączonych z pozostałymi.
- Deployów bez lawiny ponownych połączeń. Restart serwera websocket zrywa każde połączenie i wszystkie przeglądarki łączą się ponownie naraz. Strony, które były w tym czasie rozłączone, tracą też to, co wysłano w międzyczasie, chyba że coś to dla nich przechowa.
Nic z tego nie jest egzotyczne i wiele zespołów robi to dobrze. Ale to drugi system, który trzeba utrzymywać obok aplikacji tak długo, jak ma ona funkcje na żywo.
Albo niech połączenia utrzymuje chmura czasu rzeczywistego
Drugim sposobem jest hostowana usługa w roli broadcastera. Aplikacja wysyła każdy event jednym krótkim żądaniem HTTP, tak jak już robi to z broadcasterem, a usługa utrzymuje połączenia, sprawdza reguły kanałów przez Twoją aplikację i dostarcza eventy. Twoja aplikacja Laravel pozostaje zwykłą aplikacją Laravel, na dowolnym hostingu, także serverless.
Liczy się to, żeby zmiana odbyła się w ramach własnego broadcastingu Laravel, dzięki czemu Twoje eventy, kanały i kod Echo się nie zmieniają.
Broadcasting Laravel w WordPlus Cloud
Z WordPlus Cloud zmiana sprowadza się do połączenia broadcastingu. Wskazuje je Twój plik .env:
BROADCAST_CONNECTION=wordplus
WORDPLUS_SITE=s1500000007
WORDPLUS_SECRET=…
WORDPLUS_LOCAL_KEY=…Twoje kanały zostają w routes/channels.php, z jednym opcjonalnym argumentem określającym, co przechowuje każdy pokój:
// The room of an order, orders.1042, for its customer, the last 20 updates kept.
Broadcast::channel( 'orders.{order}', fn ( User $user, Order $order ) => $user->id === $order->customer_id, [ 'history' => 20 ] );Twoje eventy zostają takie, jakie są, a wysyła je broadcast( new OrderUpdated( $order ) ). W przeglądarce Echo dostaje nasz konektor zamiast swojego zwykłego:
import Echo from 'laravel-echo';
import { WordplusConnector } from '@wordplus/realtime/echo';
window.Echo = new Echo( { broadcaster: WordplusConnector, ...window.wordplusRealtimeConfig } );
Echo.private( 'orders.1042' ).listen( '.updated', ( data ) => showStatus( data.status ) );Dyrektywa @wordplusRealtime w Twoim layoucie wstawia tę konfigurację razem z zalogowanym użytkownikiem, więc strona łączy się bez żadnego wcześniejszego żądania. Dalej działa wszystko, co znasz z Echo:
- Kanały prywatne i presence, z
here(),joining()ileaving()do śledzenia, kto jest w pokoju,whisper()do informowania, że ktoś pisze, inotification()do powiadomień Laravel. - Livewire odbiera eventy w ten sam sposób, przez
#[On( 'echo-private:orders.{order.id},.updated' )]. - React i Vue korzystają z
useEcho()z pakietów Echo od Laravel, tak jak robią to starter kity. toOthers()pomija kartę, która wysłała żądanie.
A do tego to, czego sam serwer websocket nie daje:
- Żadnego serwera websocket do utrzymywania. Połączenia utrzymują nasze serwery, kolejne uruchamiają się, gdy Twoja aplikacja rośnie, a strona przechodzi z jednego na drugi bez zerwania, gdy któryś się restartuje.
- Nic nie ginie przy ponownym połączeniu. Pokój przechowuje swoje ostatnie eventy, więc strona, która wraca, dostaje to, co ją ominęło, w odpowiedniej kolejności.
- Zapieczętowane w drodze. To, co wysyła Twoja aplikacja, podróżuje zaszyfrowane kluczami, które mają tylko ona i Twoi użytkownicy.
- Rozmowy i transmisje na żywo przez to samo połączenie. Rozmowy między dwiema osobami, rozmowy grupowe i transmisje na żywo, z gotowym ekranem rozmowy i odtwarzaczem albo z Twoimi własnymi.
Przewodnik dla Laravel zawiera całą konfigurację, a demo na żywo to mały sklep zbudowany na niej, w którym status zamówienia zmienia się na „wysłane” w drugim oknie w chwili, gdy klikasz.
WordPlus Cloud for Apps ma cenę według jednoczesnych połączeń, od 1000 wzwyż, rozliczaną miesięcznie lub rocznie. Zobacz, co daje aplikacjom albo cennik dla aplikacji. Chcesz zapytać o swoją integrację? Napisz do nas.