O mnieBlogGitHub

SignalR + Azure + mikroserwisy = ? (cz.1)

03 January, 2021 - 3 min read

Mamy następuje dramatis personae: mikroserwisowe środowisko w chmurze Azure, n aplikacji klienckich. Mamy nowy feature: chcemy, aby chmura sama informowała klienty o jakiejś zmianie - pojedynczego klienta lub całą ich grupę. Załóżmy, że klientami nie są aplikacje mobilne, więc push notifications odpadają. Chcemy to ograć za pomocą SignalR. Ale jak to zrobić na Azure?

SignalR na Azure

Azure udostępnia usługę pod nazwą Azure SignalR Service. Co ona nam oferuje, skoro SignalR zawsze mogliśmy sobie "postawić" na zwykłej aplikacji ASP.NET? W największym skrócie - umożliwia spięcie SignalR także z "nietypowymi" bytami takimi jak Azure Functions oraz załatwia za nas problemy ze skalowaniem. W zależności od tego, jaką konfigurację chcemy mieć (o tym niżej), możemy uruchomić tę usługę w trybie Default lub Serverless.

Tryb Default

To jest "klasyczne" SignalR, gdzie Azure SignalR Service (dalej ASS) pełni rolę proxy pomiędzy klientami a "hub serverem", czyli aplikacją webową, na której "stawiamy" SignalR (analogicznie, jakbyśmy stawiali je w zwykłej aplikacji ASP.NET, z tym, że potrzebujemy innych nugetów). Wówczas komunikacja wygląda tak, że klienty połączone są z ASS websocketem (oczywiście, o ile dany klient wspiera websockety, no ale to wiadomo z samej natury SignalR), a także nasz "hub server" jest jest połączony kilkoma websocketami z ASS.

Do zaimplementowania mamy wówczas jedynie klasę "huba" (czyli właściwą "logikę" komunikacji) oraz kilka linijek konfiguracji w Startup.cs. To dołączone nugety zajmują się tym, żeby wystawić endpoint /negotiate, do którego uderzają klienty. Ten endpoint zwraca im już url (i token) bezpośrednio do ASS, z którym następuje połączenie websocketowe. To ważna uwaga, ponieważ Azure API Management nie wspiera socketów - więc to właściwie jedyne rozwiązanie: nasz "schowany" za gatewayem serwis wystawia tylko /negotiate, a reszta komunikacji idzie niejako z pominięciem gatewaya.

Jeśli chodzi o pricing - to w tym układzie płacimy za każdą wiadomość, która wychodzi z ASS. A zatem - jeśli to "hub serwer" sam z siebie coś wysyła, to płacimy tylko za ilość wiadomości do klientów; gdy jednak do klient coś śle do "hub serwera", to musimy zapłacić też za wiadomość wysłaną z ASS do tegoż "hub serwera". Zatem takie "echo" od klienta to w zasadzie dwie płatne wiadomości - z ASS do huba i potem (już odpowiedź) z ASS do klienta. Tak przynajmniej zrozumiałem to, co opisane jest w dokumentacji.

Tryb Serverless

A co z sytuacją, gdy naszym "hubem" ma być Azure Function? I to już nieważne, w którą stronę idzie komunikacja: od klientów czy do klientów. Problemem jest to, że funkcja nie będzie miec stałego połączenia z ASS. W tej sytuacji setup jest taki, że potrzebujemy w zasadzie dwóch funkcji:

  • tej, która wystawia endpoint /negotiate
  • oraz co najmniej drugiej do obsługi wiadomości.

Chodzi o to, że analogicznie, jak w scenariuszu Default, musimy wystawić dla klientów endpoint HTTP /negotiate, który będzie działać tak samo, jak wyżej: zwróci url do ASS oraz token. Możemy to ograć zwykłą funkcją triggerowaną przez żądanie HTTP.

Druga funkcja potrzebna jest natomiast do samej obsługi komunikatów. W zależności, w którą stronę ma ona działać, możemy mieć albo trigger HTTP (coś w stylu callbacku dla ASS, pod który ów będzie pukał, gdy klient wysyła wiadomość do huba), albo jakiś tam dowolny trigger typu kolejka lub cokolwiek, jeśli chcemy sami pchać wiadomości do klientów.

Jedną i drugą funckję "ogrywamy" odpowiednim nugetem + atrybutami, które wstrzykują do funkcji klasy, które umożliwiają albo dostęp do konfiguracji, albo komunikację z klientami.

To be continued...

Jak to wszystko się ma do mikroserwisów - o tym w części drugiej. :)

© 2021, Built with Gatsby