Usługa biuletynu w Laravel: jak połączyliśmy wysyłanie wiadomości e-mail i SMS dla wszystkich usług wewnętrznych
W dużym projekcie każda usługa wysyłała e-maile i SMS-y na swój sposób: powielanie kodu, brak Pulpitu nawigacyjnego statusu, długie poprawki. Zaprojektowaliśmy kompleksową usługę biuletynu w Laravel i RabbitMQ z trzech rozwiązań-dashboard, API i nadawcy. Dostawcy łączą się raz, statusy są widoczne za pośrednictwem webhooków agregatorów, a zespół nie marnuje już czasu na zduplikowane integracje.
Problem: wysyłka jako wąskie gardło
Zacznijmy od kontekstu. Uczestniczyliśmy w dużym projekcie obejmującym zestaw różnych paneli użytkownika na platformie 1C-Bitrix. Każde rozwiązanie pełniło określoną funkcję. Uwierzytelnianie w każdym z nich odbywało się przez OAuth 2.0 za pośrednictwem naszego modułu napisanego w Laravelu. Większość serwisów wysyłała klientom wiadomości e-mail, a część korzystała również z SMS-ów.
Na pierwszy rzut oka wszystko działało. Jednak po bliższym przyjrzeniu się zauważyliśmy narastający dług techniczny:
- Każdy serwis miał własną integrację z dostawcami usług wysyłkowych. Ten sam kod odpowiedzialny za wysyłkę był powielany w każdym rozwiązaniu.
- Zespół wsparcia był wspólny, ale kod wysyłki rozproszony po wszystkich serwisach — błędy trzeba było poprawiać w kilku miejscach.
- Brakowało dashboardu. Nie można było sprawdzić, czy wiadomość została wysłana i jaki ma status.
- Zmiany w mechanizmach wysyłki wdrażano osobno w każdym serwisie. Przy dużym obciążeniu zespołu biznes długo czekał na poprawki.
Każda kolejna zmiana stawała się małym projektem: trzeba było równolegle modyfikować kilka serwisów, testować każdą integrację i pamiętać, który dostawca jest podłączony w którym miejscu.
Pomysł: jeden serwis zamiast modułu
Początkowo zadanie brzmiało skromnie — opracować moduł wysyłki wiadomości dla serwisu uwierzytelniania. Zaproponowaliśmy jednak biznesowi szersze rozwiązanie: stworzenie wspólnego serwisu wysyłkowego dla wszystkich serwisów wewnętrznych. Pomysł został zaakceptowany.
Dlaczego było to korzystniejsze niż kolejny moduł?
- Jedna integracja zamiast kilku. Dostawców podłącza się raz, a nie osobno w każdym serwisie.
- Jednolity interfejs API dla wszystkich serwisów wewnętrznych. Wysyłanie wiadomości i pobieranie ich statusów odbywa się według tego samego protokołu.
- Centralny dashboard ze statusami wysyłek i rejestrem błędów. Zespół wsparcia zyskał dostęp do informacji o wysyłanych wiadomościach.
- Zmiany szablonów i logiki w jednym miejscu. Biznes szybciej otrzymuje potrzebne aktualizacje.
Dodatkowym impulsem było to, że wszystkie serwisy korzystały z Mailchimp. Ze względu na spodziewaną blokadę tej platformy konieczne było przejście na nowe rozwiązanie dla rynku rosyjskiego.
Architektura serwisu wysyłkowego
Podzieliliśmy system na trzy komponenty. Każdy pełni określoną funkcję i komunikuje się z pozostałymi na podstawie jasno zdefiniowanych kontraktów.
- Dashboard — interfejs webowy
Ten komponent jest dostępny z poziomu przeglądarki. Skupia wszystkie informacje operacyjne:
- Dane dotyczące wysyłki wiadomości e-mail i SMS
- Klientów API serwisu i operacje zarządzania nimi
- Rejestr błędów
- Szablony wiadomości e-mail i SMS
To właśnie tutaj frontend developer przygotowuje i edytuje szablony.
- Komponent API
Przyjmuje zlecenia dla poszczególnych kanałów: zgłoszenia incydentów w OMNITRACKER, wiadomości e-mail przez integracje z DashaMail, UniSender i własnym serwisem wysyłkowym oraz SMS-y przez integracje z MTS Marketolog i MTS Communicator. Po walidacji żądania inicjuje utworzenie zadań w RabbitMQ.
- Komponent wysyłkowy
Jedynym sposobem przekazywania mu zadań jest kolejka RabbitMQ. Komponent pobiera zadania, gdy pojawią się w kolejce. Szablony pobiera z pierwszego komponentu, czyli dashboardu, za pośrednictwem API.
Taki podział zapewnił elastyczność systemu: komponent wysyłkowy nie musi znać wewnętrznej logiki API ani dashboardu. Obsługuje zadania z kolejki, a szablony pobiera przez API dashboardu. Ułatwia to skalowanie i izolowanie awarii.
Przebieg działania i RabbitMQ
Prześledźmy cały proces — od zmiany szablonu do uzyskania statusu wysyłki.
- Biznes zgłasza potrzebę zmiany szablonu wiadomości e-mail lub przygotowania nowego.
- Frontend developer tworzy albo modyfikuje szablon w komponencie odpowiedzialnym za zarządzanie szablonami. Następnie wdrażamy zmiany.
- Zespoły odpowiedzialne za serwisy wewnętrzne otrzymują instrukcję korzystania z nowego lub zmodyfikowanego szablonu przez API: jak wysłać wiadomość i pobrać jej status.
- Serwis kliencki wywołuje API, inicjując wysyłkę. Serwis wysyłkowy waliduje żądanie, umieszcza zadanie w kolejce, a następnie je przetwarza.
- Serwis oczekuje na aktualizacje statusu wysyłki przekazywane przez webhooki dostawców.
Do serwisu podłączono trzech dostawców usług e-mail i dwóch dostawców SMS. Taki układ zapewnia redundancję: jeśli jeden dostawca jest niedostępny, wysyłka odbywa się przez innego.
Dlaczego RabbitMQ?
Kolejka wiadomości stała się ogniwem łączącym komponent API z komponentem wysyłkowym. Dało to kilka istotnych korzyści:
- Asynchroniczność. Serwis kliencki nie czeka na faktyczne wysłanie wiadomości — otrzymuje potwierdzenie przyjęcia zadania.
- Niezawodność. Zadania nie giną podczas awarii, ponieważ kolejka przechowuje je do momentu przetworzenia.
- Rozdzielenie odpowiedzialności. Komponent wysyłkowy można skalować niezależnie od pozostałych części systemu.
Co ważne, skonfigurowaliśmy obsługę RabbitMQ tak, aby wiadomość była potwierdzana i usuwana z kolejki dopiero po pomyślnym wykonaniu zadania. Dzięki temu nie tracimy zadań, które zostały pobrane do przetworzenia, ale nie zostały ukończone.
Rezultaty i wnioski
Po wdrożeniu serwisu wysyłkowego serwisy wewnętrzne nie muszą już przebudowywać swoich integracji. Korzystają po prostu ze wspólnego, ustandaryzowanego interfejsu wysyłki.
Najważniejsze rezultaty:
- Skrócił się czas poświęcany na rozwój i utrzymanie wysyłki w serwisach wewnętrznych.
- Uwolniony czas zespołu przeznaczono na funkcje ważniejsze dla biznesu.
- Pojawiła się przejrzystość. Dashboard pokazuje statusy wysyłek, które wcześniej nie były widoczne.
- Aktualizacje szablonów stały się szybsze. Biznes nie musi już długo czekać — zmiany wprowadza się w jednym miejscu.
Najważniejsze wnioski z tego projektu:
- Centralizacja wysyłki opłaca się, gdy istnieje kilka serwisów, a integracje są powielane. Jeden wspólny serwis oznacza mniej kodu, mniej błędów i szybsze wdrażanie zmian.
- Podział na dashboard, API i komponent wysyłkowy, z kolejką łączącą API z komponentem wysyłkowym, zapewnia elastyczność i skalowalność. Każdy komponent można zmieniać i rozwijać niezależnie.
- Webhooki dostawców zapewniają wcześniej niedostępną widoczność statusów. Biznes może sprawdzić, czy wiadomość została wysłana.
- Warto proponować biznesowi szersze rozwiązania. Zadanie „zbudować moduł” przerodziło się w usprawnienie architektury, które zaoszczędziło czas całego zespołu.
Jeśli macie kilka serwisów, z których każdy na własny sposób wysyła wiadomości e-mail i SMS, warto rozważyć wspólny serwis wysyłkowy. To jeden z tych przypadków, w których inwestycja w architekturę szybko się zwraca.