12 sie 2025·6 min czytania

Triggery vs workery w tle dla niezawodnych powiadomień

Dowiedz się, kiedy triggery, a kiedy workery w tle są bezpieczniejsze dla powiadomień — praktyczne wskazówki dotyczące retry, granic transakcji i zapobiegania duplikatom.

Triggery vs workery w tle dla niezawodnych powiadomień

Dlaczego dostarczanie powiadomień zawodzi w prawdziwych aplikacjach

Powiadomienia wydają się proste: użytkownik coś robi, potem idzie e-mail lub SMS. Większość rzeczywistych awarii sprowadza się do timingu i duplikacji. Wiadomości są wysyłane zanim dane zostaną naprawdę zapisane, albo zostają wysłane dwukrotnie po częściowej awarii.

„Powiadomienie” może oznaczać wiele rzeczy: e-maile z potwierdzeniami, SMS-y z jednorazowymi kodami, push, wiadomości w aplikacji, powiadomienia na Slack lub Telegram, albo webhook do innego systemu. Wspólny problem jest zawsze ten sam: koordynujesz zmianę w bazie danych z czymś poza aplikacją.

Świat zewnętrzny jest nieporządny. Dostawcy mogą być wolni, zwracać timeouty albo zaakceptować żądanie, podczas gdy twoja aplikacja nigdy nie dostanie sukcesu. Twoja aplikacja może paść lub zrestartować się w połowie żądania. Nawet „udane” wysyłki mogą zostać powtórzone z powodu retry infrastruktury, restartów workerów lub użytkownika klikającego przycisk ponownie.

Typowe przyczyny zawodnego dostarczania powiadomień to timeouty sieciowe, awarie dostawcy lub limity, restart aplikacji w złym momencie, retry które ponownie uruchamiają tę samą logikę bez unikalnej blokady, oraz projektowanie, w którym zapis do bazy i zewnętrzna wysyłka dzieją się jako jeden krok.

Gdy ludzie mówią o „niezawodnych powiadomieniach”, zwykle mają na myśli jedno z dwóch:

  • dostarczyć dokładnie raz, albo
  • przynajmniej nigdy nie zdublować (duplikaty często są gorsze niż opóźnienie).

Uzyskanie obu cech — szybkości i pełnego bezpieczeństwa — jest trudne, więc trzeba wybierać kompromisy między szybkością, bezpieczeństwem i złożonością.

Dlatego wybór między triggerami a workerami w tle to nie tylko debata architektoniczna. Chodzi o to, kiedy wysyłka może się odbyć, jak obsługiwane są porażki i retry, oraz jak zapobiegać podwójnym e-mailom lub SMS-om gdy coś pójdzie nie tak.

Triggery i workery w tle: co to znaczy

Gdy porównuje się triggery z workerami, w rzeczywistości porównuje się miejsce, gdzie działa logika powiadomień i jak mocno jest związana z akcją, która ją wywołała.

Trigger to „zrób to teraz, gdy X się stanie”. W wielu aplikacjach oznacza to wysłanie e-maila lub SMS-a bezpośrednio po akcji użytkownika, w tym samym żądaniu webowym. Triggery mogą też żyć na poziomie bazy danych: trigger bazodanowy uruchamia się automatycznie po wstawieniu lub aktualizacji wiersza. Oba typy wydają się natychmiastowe, ale dziedziczą timing i ograniczenia tego, co je wywołało.

Worker w tle to „zrób to wkrótce, ale nie na pierwszym planie”. To oddzielny proces, który pobiera zadania z kolejki i próbuje je wykonać. Główna aplikacja zapisuje, co trzeba zrobić, a zwraca odpowiedź szybko, podczas gdy worker obsługuje wolniejsze, podatne na błędy części, jak wywołania providerów e-mail/SMS.

„Zadanie” to jednostka pracy, którą worker przetwarza. Zwykle zawiera kogo powiadomić, który szablon, jakie dane, obecny status (queued, processing, sent, failed), ile było prób i czasami zaplanowany termin.

Typowy przepływ powiadomień wygląda tak: przygotowujesz treść wiadomości, enqueujesz zadanie, wysyłasz przez providera, zapisujesz wynik, a potem decydujesz o retry, zatrzymaniu lub alarmie dla kogoś.

Granice transakcji: kiedy rzeczywiście bezpiecznie wysyłać

Granica transakcji to linia między „próbowaliśmy zapisać” a „to jest naprawdę zapisane”. Dopóki baza nie commitnie, zmiana może zostać wycofana. To ważne, bo powiadomień nie da się łatwo cofnąć.

Jeśli wyślesz e-mail lub SMS przed commitem, możesz powiadomić kogoś o czymś, co się nigdy nie wydarzyło. Klient może dostać „Twoje hasło zostało zmienione” lub „Twoje zamówienie zostało potwierdzone”, a potem zapis nie przejdzie z powodu błędu lub timeoutu. Teraz użytkownik jest zdezorientowany, a support ma rozwiązywać problem.

Wysyłanie z poziomu triggera bazodanowego kusi, bo uruchamia się automatycznie przy zmianie danych. Ale haczyk jest taki, że triggery działają w tej samej transakcji. Jeśli transakcja zostanie wycofana, mogłeś już wywołać provider e-mail/SMS.

Trigery bazodanowe też są trudniejsze do obserwacji, testowania i bezpiecznego retry. Gdy robią wolne wywołania zewnętrzne, mogą przytrzymywać blokady dłużej niż oczekujesz i utrudniać diagnozowanie problemów z bazą.

Bezpieczniejsze podejście to pomysł outbox: zapisz intencję powiadomienia jako dane, commitnij ją, a potem wyślij.

W tej samej transakcji wykonujesz zmianę biznesową i wstawiasz wiersz outbox opisujący wiadomość (kto, co, kanał, plus unikalny klucz). Po commicie worker w tle czyta zaległe wiersze outbox, wysyła wiadomość, a potem oznacza je jako wysłane.

Natychmiastowe wysyłki mogą być w porządku dla mało istotnych informacji, gdzie pomyłka jest akceptowalna, np. „Przetwarzamy twoje żądanie”. Dla wszystkiego, co musi odpowiadać finalnemu stanowi, poczekaj do commitu.

Retry i obsługa błędów: gdzie co wygrywa

Retry są zwykle czynnikiem decydującym.

Triggery: szybkie, ale kruche przy błędach

Większość projektów opartych na triggerach nie ma dobrego sposobu na retry.

Jeśli trigger wywołuje providera e-mail/SMS i wywołanie się nie uda, zwykle masz dwa złe wybory:

  • przerwij transakcję (blokując oryginalną zmianę), albo
  • przechowaj błąd w ciszy (i stracisz powiadomienie bez śladu).

Żadne z nich nie jest akceptowalne, gdy zależy ci na niezawodności.

Próbowanie loopów lub opóźnień wewnątrz triggera może pogorszyć sprawę, bo trzymasz transakcję otwartą dłużej, zwiększasz czas blokad i spowalniasz bazę. Jeśli baza lub aplikacja padną w trakcie wysyłki, często nie da się ustalić, czy provider otrzymał żądanie.

Workery w tle: zaprojektowane pod retry

Worker traktuje wysyłkę jako oddzielne zadanie z własnym stanem. Dzięki temu naturalnie można retryować tylko wtedy, kiedy to ma sens.

W praktyce retryujesz błędy tymczasowe (timeouty, przerywane problemy sieciowe, błędy serwera, limity z dłuższym oczekiwaniem). Zazwyczaj nie retryujesz problemów trwałych (nieprawidłowe numery, źle sformatowane e-maile, twarde odrzuty jak wypisani subskrybenci). Dla „nieznanych” błędów limitujesz próby i pokazujesz stan.

Backoff zapobiega, żeby retry pogarszały sytuację. Zacznij od krótkiego oczekiwania, potem je zwiększaj (np. 10s, 30s, 2m, 10m) i zatrzymaj po określonej liczbie prób.

Aby to przetrwało deployy i restarty, przechowuj stan retry przy każdym zadaniu: licznik prób, czas następnej próby, ostatni błąd (krótki i czytelny), czas ostatniej próby oraz jasny status jak pending, sending, sent, failed.

Jeśli aplikacja zrestartuje się w trakcie wysyłki, worker może ponownie sprawdzić utknięte zadania (np. status = sending ze starym timestampem) i bezpiecznie je retryować. Tutaj idempotencja jest kluczowa, by retry nie powielały wysyłek.

Zapobieganie duplikatom e-maili i SMS-ów przez idempotencję

Wdróż bezpieczny domyślny wzorzec
Szybko zaprojektuj cały wzorzec: model danych, logikę biznesową i UI do monitoringu.
Wypróbuj AppMaster

Idempotencja oznacza, że możesz uruchomić tę samą akcję „wyślij powiadomienie” wielokrotnie, a użytkownik i tak otrzyma ją tylko raz.

Typowy przypadek duplikacji to timeout: twoja aplikacja wywołuje providera, żądanie timeoutuje, a ty retryujesz. Pierwsze żądanie mogło się jednak powieść, więc retry tworzy duplikat.

Praktyczne rozwiązanie to nadanie każdej wiadomości stabilnego klucza i traktowanie tego klucza jako jedynego źródła prawdy. Dobre klucze opisują, co wiadomość znaczy, a nie kiedy próbowałeś ją wysłać.

Powszechne podejścia to:

  • wygenerowane notification_id tworzone w momencie, gdy decydujesz „ta wiadomość ma istnieć”, albo
  • klucz pochodzący z logiki biznesowej jak order_id + template + recipient (tylko jeśli to naprawdę definiuje unikalność).

Potem przechowaj ledger wysyłek (często sama tabela outbox) i każdorazowo konsultuj go przed wysłaniem. Trzymaj statusy proste i widoczne: created (zdecydowano), queued (gotowe), sent (potwierdzone), failed (potwierdzona porażka), canceled (już niepotrzebne). Krytyczna zasada: pozwól tylko na jeden aktywny rekord na klucz idempotencji.

Idempotencja po stronie providera może pomóc, gdy jest wspierana, ale nie zastępuje twojego ledgeru. Nadal musisz obsłużyć retry, deployy i restarty workerów.

Traktuj też „nieznane” wyniki priorytetowo. Jeśli żądanie timeoutowało, nie wysyłaj od razu ponownie. Oznacz je jako oczekujące potwierdzenia i retryuj bezpiecznie, sprawdzając status dostawy u providera, jeśli to możliwe. Jeśli nie możesz potwierdzić, opóźnij i zgłoś problem zamiast podwójnej wysyłki.

Bezpieczny domyślny wzorzec: outbox + worker w tle (krok po kroku)

Jeśli chcesz bezpiecznego domyślnego rozwiązania, wzorzec outbox plus worker jest trudny do pobicia. Trzyma wysyłanie poza transakcją biznesową, jednocześnie gwarantując, że intencja wysyłki jest zapisana.

Przepływ

Traktuj „wyślij powiadomienie” jako dane, które zapisujesz, a nie akcję, którą odpalasz.

Zapisujesz zmianę biznesową (np. aktualizację statusu zamówienia). W tej samej transakcji wstawiasz wiersz outbox z odbiorcą, kanałem (email/SMS), szablonem, payloadem i kluczem idempotencji. Commitujesz transakcję. Dopiero po tym punkcie można coś wysyłać.

Worker w tle regularnie pobiera zaległe wiersze outbox, wysyła je i zapisuje wynik.

Dodaj prosty krok „claim”, żeby dwa workery nie wzięły tego samego wiersza. Może to być zmiana statusu na processing lub znacznik czasowy blokady.

Blokowanie duplikatów i obsługa błędów

Duplikaty często zdarzają się, gdy wysyłka się powiodła, ale aplikacja padła przed zapisaniem „sent”. Rozwiązujesz to, czyniąc zapis „oznacz jako wysłane” bezpiecznym do powtórzenia.

Użyj reguły unikalności (np. unikatowy constraint na kluczu idempotencji i kanale). Retryuj z jasnymi zasadami: ograniczona liczba prób, rosnące opóźnienia i tylko dla błędów retryowalnych. Po ostatniej próbie przenieś zadanie do stanu dead-letter (np. failed_permanent), żeby ktoś mógł to ręcznie przejrzeć i przetworzyć ponownie.

Monitoring może pozostać prosty: liczniki pending, processing, sent, retrying i failed_permanent oraz najstarszy pending timestamp.

Przykład: gdy zamówienie przechodzi z „Packed” do „Shipped”, aktualizujesz wiersz order i tworzysz jeden outbox z kluczem idempotencji order-4815-shipped. Nawet jeśli worker padnie w trakcie wysyłki, ponowne uruchomienia nie podwielą wysyłki, ponieważ zapis „sent” jest chroniony unikalnym kluczem.

Kiedy workery w tle są lepszym wyborem

Zaprojektuj jasne zasady retry
Użyj logiki drag and drop do obsługi backoffu, prób i błędów permanentnych.
Rozpocznij

Trigery bazodanowe dobrze reagują w chwili zmiany danych. Ale jeśli celem jest „dostarcz powiadomienie niezawodnie w niestabilnych warunkach”, workery zwykle dają więcej kontroli.

Workery są lepsze, gdy potrzebujesz wysyłek czasowych (przypomnienia, digesty), dużej przepustowości z limitami i backpressure, tolerancji na zmienność providerów (429, powolne odpowiedzi, krótkie awarie), wieloetapowych workflow (wyślij, poczekaj na dostawę, potem follow-up) lub zdarzeń między systemami, które trzeba zreconciliować.

Przykład: pobierasz opłatę, potem wysyłasz SMS z potwierdzeniem, potem e-mail z fakturą. Jeśli SMS zawiedzie z powodu problemu bramki, chcesz, żeby zamówienie pozostało opłacone i dało się bezpiecznie spróbować ponownie później. Umieszczenie tej logiki w triggerze miesza „dane są poprawne” z „dostawca jest dostępny teraz”, co jest ryzykowne.

Workery też ułatwiają operacje: możesz wstrzymać kolejkę podczas incydentu, sprawdzić błędy i retryować z opóźnieniami.

Powszechne błędy prowadzące do utraconych lub zdublowanych wiadomości

Daj wsparciu czytelne narzędzia
Dodaj widoki administracyjne do przeglądu nieudanych wiadomości i bezpiecznego ponownego przetwarzania.
Stwórz aplikację

Najszybsza droga do zawodnych powiadomień to „po prostu wyślij to” tam, gdzie wygodnie, i liczyć, że retry uratuje sytuację. Niezależnie od tego, czy używasz triggerów czy workerów, szczegóły dotyczące stanu i obsługi błędów zdecydują, czy użytkownik dostanie jedną wiadomość, dwie, czy żadnej.

Typowa pułapka to wysyłanie z triggera i zakładanie, że on nie zawiedzie. Triggery działają w transakcji, więc każde wolne wywołanie providera może zatrzymać zapis, wywołać timeout lub blokować tabele dłużej niż zakładałeś. Gorzej, jeśli wysyłka zawiedzie i wycofasz transakcję — możesz wysłać raz, a potem przy retry wysłać ponownie.

Błędy, które powtarzają się najczęściej:

  • Retryowanie wszystkiego jednakowo, w tym błędów permanentnych (zły e-mail, zablokowany numer).
  • Brak separacji queued od sent, więc nie możesz określić, co bezpiecznie retryować po awarii.
  • Używanie timestampów jako kluczy deduplikujących, co sprawia, że retry omija unikalność.
  • Wywołania providerów w ścieżce żądania użytkownika (checkout i submit formularza nie powinny czekać na bramki).
  • Traktowanie timeoutów providerów jako „nie dostarczono”, gdy wiele z nich to faktycznie „nieznane”.

Prosty przykład: wysyłasz SMS, provider timeoutuje i retryujesz. Jeśli pierwsze żądanie jednak powiodło się, użytkownik dostanie dwa kody. Naprawa to zapisanie stabilnego klucza idempotencji (np. notification_id), oznaczenie wiadomości jako queued przed wysłaniem i oznaczenie jako sent dopiero po wyraźnym sukcesie.

Szybkie kontrole przed wdrożeniem powiadomień

Większość błędów powiadomień to nie problem narzędzia, lecz timingu, retry i brakujących zapisów.

Potwierdź, że wysyłasz dopiero po tym, jak zapis w bazie jest bezpiecznie zatwierdzony. Jeśli wysyłasz wewnątrz tej samej transakcji, a potem się ona rollbackuje, użytkownicy mogą dostać wiadomość o czymś, co nigdy się nie wydarzyło.

Następnie nadaj każdemu powiadomieniu unikalną tożsamość. Daj każdej wiadomości stabilny klucz idempotencji (np. order_id + event_type + channel) i egzekwuj go w magazynie, żeby retry nie stworzyły nowej "nowej" wiadomości.

Przed wydaniem sprawdź podstawy:

  • Wysyłanie dzieje się po commicie, a nie w trakcie zapisu.
  • Każde powiadomienie ma unikalny klucz idempotencji, a duplikaty są odrzucane.
  • Retry są bezpieczne: system może uruchomić to samo zadanie ponownie i wysłać co najwyżej raz.
  • Każda próba jest zapisana (status, last_error, timestamps).
  • Próby mają limit, a utknięte elementy mają jasne miejsce do przeglądu i ponownego przetworzenia.

Testuj zachowanie przy restarcie celowo. Zabić workera w trakcie wysyłki, zrestartować i sprawdzić, że nic się nie zdublowało. Zrób to samo przy obciążonej bazie.

Prosty scenariusz do walidacji: użytkownik zmienia numer telefonu, potem wysyłasz SMS weryfikacyjny. Jeśli provider timeoutuje, aplikacja retryuje. Przy dobrym kluczu idempotencji i logu prób albo wyślesz raz, albo bezpiecznie spróbujesz ponownie później, ale nie zasypiesz użytkownika spamem.

Przykładowy scenariusz: aktualizacje zamówienia bez podwójnej wysyłki

Śledź każdą próbę
Stwórz prosty ledger ze statusami: pending, processing, sent i failed.
Zacznij teraz

Sklep wysyła dwa typy wiadomości: (1) e-mail potwierdzający zamówienie bezpośrednio po płatności oraz (2) SMS-y przy statusach "Out for delivery" i "Delivered".

Co idzie nie tak, gdy wysyłasz za wcześnie (np. w triggerze): krok płatności zapisuje wiersz orders, trigger odpala i wysyła e-mail, a potem capture płatności nie udaje się chwilę później. Masz wtedy "Dziękujemy za zamówienie" dla zamówienia, które nie stało się realne.

Teraz odwrotny problem: status dostawy zmienia się na "Out for delivery", wywołujesz providera SMS, a provider timeoutuje. Nie wiesz, czy wiadomość dotarła. Jeśli od razu retryujesz, ryzykujesz dwa SMS-y. Jeśli nie retryujesz, ryzykujesz brak wysyłki.

Bezpieczniejszy przepływ używa outbox + worker. Aplikacja commituje zamówienie lub zmianę statusu i w tej samej transakcji zapisuje wiersz outbox typu „wyślij szablon X do użytkownika Y, kanał SMS, klucz idempotencji Z”. Dopiero po commicie worker dostarcza wiadomości.

Prosta oś czasu:

  • Płatność się powiedzie, transakcja commit, wiersz outbox dla e-maila potwierdzającego jest zapisany.
  • Worker wysyła e-mail i oznacza outbox jako sent z ID wiadomości od providera.
  • Status dostawy się zmienia, transakcja commit, wiersz outbox dla aktualizacji SMS jest zapisany.
  • Provider timeoutuje, worker oznacza outbox jako retryowalny i próbuje później ponownie używając tego samego klucza idempotencji.

Podczas retry wiersz outbox jest jedynym źródłem prawdy. Nie tworzysz drugiej próby wysyłki, tylko kończysz pierwotną.

Dla supportu jest to też czytelniejsze. Widzisz wiadomości utknięte w failed z ostatnim błędem (timeout, zły numer, zablokowany e-mail), liczbą prób i informacją, czy bezpiecznie retryować bez duplikatów.

Następne kroki: wybierz wzorzec i zaimplementuj go porządnie

Wybierz domyślne rozwiązanie i zapisz je. Niespójne zachowanie zwykle wynika z losowego mieszania triggerów i workerów.

Zacznij od małego outboxa i jednej pętli workera. Pierwszy cel to poprawność: zapisz, co zamierzasz wysłać, wyślij po commicie i oznacz jako wysłane dopiero przy potwierdzeniu providera.

Prosty plan wdrożenia:

  • Zdefiniuj zdarzenia (order_paid, ticket_assigned) i kanały, których mogą używać.
  • Dodaj tabelę outbox z polami event_id, recipient, payload, status, attempts, next_retry_at, sent_at.
  • Zbuduj jednego workera, który polluje pending wiersze, wysyła i aktualizuje status w jednym miejscu.
  • Dodaj idempotencję z unikalnym kluczem na wiadomość i logiką "nie rób nic jeśli już wysłane".
  • Podziel błędy na retryowalne (timeouty, 5xx) i permanentne (zły numer, zablokowany e-mail).

Zanim zwiększysz skalę, dodaj podstawową widoczność: licznik pending, rate błędów i wiek najstarszej oczekującej wiadomości. Jeśli najstarsze pending się wydłuża, prawdopodobnie masz utknięty worker, awarię providera lub błąd w logice.

Jeśli budujesz w AppMaster (appmaster.io), ten wzorzec pasuje prosto: zamodeluj outbox w Data Designerze, zapisz zmianę biznesową i wiersz outbox w jednej transakcji, potem uruchom logikę wysyłania i retry w oddzielnym procesie w tle. Ta separacja to właśnie to, co utrzymuje dostarczanie powiadomień niezawodne nawet gdy providerzy lub deploye się nie zachowują idealnie.

FAQ

Should I use triggers or background workers for notifications?

Background workers zwykle są bezpieczniejszym domyślnym wyborem, ponieważ wysyłanie jest wolne i podatne na błędy, a workery są zaprojektowane do retryów i dają dobrą widoczność. Triggery mogą być szybkie, ale są ściśle związane z transakcją lub żądaniem, które je wywołało, co utrudnia obsługę błędów i unikanie duplikatów.

Why is it risky to send a notification before the database commit?

Ryzykowne, ponieważ zapis w bazie może zostać wycofany. Możesz wysłać powiadomienie o zamówieniu, zmianie hasła lub płatności, która ostatecznie nie została zatwierdzona, a wiadomości e-mail lub SMS nie da się cofnąć po wysłaniu.

What’s the biggest problem with sending from a database trigger?

Trigger bazodanowy działa w tej samej transakcji co zmiana wiersza. Jeśli wywoła provider e-mail/SMS, a potem transakcja nie przejdzie, mogłeś wysłać prawdziwą wiadomość o zmianie, która się nie utrwaliła, albo zablokować zapis z powodu powolnego zewnętrznego wywołania.

What is the outbox pattern in plain terms?

Wzorzec outbox zapisuje intencję wysłania jako wiersz w bazie danych w tej samej transakcji co zmiana biznesowa. Po commicie worker odczytuje zaległe wiersze outbox, wysyła wiadomość i oznacza ją jako wysłaną — dzięki temu timing i retry są znacznie bezpieczniejsze.

What should I do when an email/SMS provider request times out?

Gdy provider timeoutuje, wynik często jest „nieznany”, a nie „nieudany”. Dobry system zapisuje próbę, opóźnia kolejne próby i ponawia je bezpiecznie, używając tej samej tożsamości wiadomości, zamiast od razu wysyłać ponownie i ryzykować duplikat.

How do I prevent duplicate emails or SMS when retries happen?

Stosuj idempotencję: nadaj każdemu powiadomieniu stabilny klucz reprezentujący, co wiadomość oznacza (a nie kiedy próbowałeś ją wysłać). Zapisz ten klucz w ledgerze (często tabela outbox) i wymuś jedną aktywną rekordację na klucz, żeby retry kończył tę samą wiadomość zamiast tworzyć nową.

Which errors should I retry vs treat as permanent?

Powtarzaj błędy tymczasowe, takie jak timeouty, odpowiedzi 5xx czy limity (z odpowiednim opóźnieniem). Nie ponawiaj błędów permanentnych: nieprawidłowe adresy, zablokowane numery czy hard bounce—oznacz je jako nieudane i wyświetl, żeby ktoś mógł poprawić dane zamiast spamować retryami.

How do background workers handle restarts or crashes mid-send?

Worker może zeskanować zadania utknięte w stanie sending dłużej niż oczekiwano, przenieść je z powrotem na retryowalne i spróbować ponownie z backoffem. To działa bezpiecznie tylko wtedy, gdy każde zadanie ma zapisany stan (licznik prób, znaczniki czasowe, ostatni błąd) i idempotencja zapobiega podwójnej wysyłce.

What job data do I need to make notification delivery observable?

Oznacza to, że nie będziesz zgadywać, czy warto retryować. Przechowuj jasne statusy jak pending, processing, sent i failed, oraz licznik prób i ostatni błąd. Dzięki temu wsparcie i debugowanie są praktyczne, a system może się bezpiecznie odzyskać.

How would I implement this pattern in AppMaster?

Zamodeluj tabelę outbox w Data Designerze, wykonaj aktualizację biznesową i wstaw wiersz outbox w jednej transakcji, a następnie uruchom logikę wysyłania i retry w oddzielnym procesie w tle. Trzymaj jeden klucz idempotencji na wiadomość i zapisuj próby, żeby deployy, retry i restarty workerów nie tworzyły duplikatów.

Łatwy do uruchomienia
Stworzyć coś niesamowitego

Eksperymentuj z AppMaster z darmowym planem.
Kiedy będziesz gotowy, możesz wybrać odpowiednią subskrypcję.

Rozpocznij