Zapewnienie transakcji

0

Witam,
mam tabelę bazodanową, w której znajdują się informacje o danych odbiorców maili oraz informacje o statusie wysyłki (1 - udało się, 0 nie udało się). Wysyłamy maile do skutku - tzn. aż się uda wysłać (zazwyczaj będzie to jedna próba). Jak się uda wysłać maila to zmieniamy status dla danego rekordu na 1.

Problem:
co w przypadku kiedy uda się wysłać maila, ale nie uda się zaktualizować rekordu na bazie danych (np. timeout)? - mail zostanie wysłany ponownie. Jak zapewnić taką "transakcję"? Czy są jakieś mechanizmy pozwalające na taką operację czy raczej trzeba dopisać coś ala serializacja do pliku aktualnego stanu i deserializacje przed próbą wysłania?

0

Tak na prawde masz do czynienia z dwoma transakcjami:

  • pierwsza to aktualizacja bazy danych
  • druga to wyslanie maila

Chcesz, zeby operacja zlozona z tych dwoch transakcji, byla takze transakcja. Bylo by idealnie gdybys zamiast dwoch transakcji mial jedna transakcje z dwoma operacjami: wyslanie maila i aktualizacja bazy. Niestety obecnie tak sie nie da (chociaz Microsoft dazy do tego, zeby to zmienic wbudowujac w jadro obsluge transakcji).
Zla wiadomosc jest taka, ze nie da sie zapewnic transakcyjnosci dwoch osobnych transakcji, ktore polegaja na sobie. Dobra wiadomosc: istnieje algorytm, ktory minimimalizuje szanse na niepowodzenie. Nazywa sie 2 phase commit i czesc baz danych go supportuje.
Polega on na tym, ze przed wyslaniem maila wysylasz rzadanie do bazy danych: PREPARE FOR COMMIT. Baza danych sprawdza czy obecna transakcje da sie w tej chwili zacommitowac i zwraca status. Jezeli status mowi, ze transakcje da sie zacommitowac to probujesz wyslac maila. Jezeli nie udalo sie wyslac to robisz ROLLBACK. Jezeli udalo sie wyslac to robisz wlasciwego COMMITA. W tym schemacie jest pewne okno czasowe pomiedzy PREPARE FOR COMMIT i faktycznym wyslaniem maila, w ktorym sytuacja moze ulec zmianie i wlasciwy COMMIT sie nie powiedzie (np. dlatego, ze siec padla). Jednak te okno czasowe jest waskie przez co minimalizujesz szanse na niepowodzenie.
Tak od praktycznej strony to raczej nie uruchamialbym calej maszynerii 2-phase commita tylko dla wyslania maila. Uzytkownik nie umrze jezeli dostanie 2 maile zamiast jednego.

0

Łatwiej byłoby chyba zapewnić transakcyjność operacji wysyłając maila z serwera bazy danych SZBD.

0

Dzięki wielkie za odpowiedzi.
W takim razie trzeba coś kombinować. Myślałem, że może istnieją jakieś mechanizmy zapewniające taką "transakcję". Co do wysyłania przez serwer bazodanowy to nie jestem pewny czy bardzo duża liczba maili do wysłania nie spowodowałaby bardzo dużego obciążenia serwera baz danych - trzeba sprawdzić. Dzięki.

0

Łatwiej byłoby chyba zapewnić transakcyjność operacji wysyłając maila z serwera bazy danych.

Co jesli program musi sie wykonywac na innej stacji niz serwer bazy danych? Wysylajac maila z serwera bazy danych upewniasz sie tylko, ze stacja sie nie zawiesila (lub ze siec wciaz dziala). To samo mozesz osiagnac pingujac serwer (niekoniecznie mowie o poleceniu ping). Wciaz serwer po wyslaniu maila moze sie zawiesic, proces bazy danych moze sie zawiesic lub zcrashowac, commit transakcji moze sie nie powiesc ze wzgledu na wspolbiezne modyfikacje tych samych danych przez inne transakcje. Korzysci takiego rozwiazania sa niewielkie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1