2013-07-02 21 views
10

Aby uprościć mój problem, mamWiosna/RabbitMQ: zarządzanie transakcjami

app1 z metodą @Transactionnal createuser():

  • Włóż nowy użytkownik w bazie
  • Dodaj wiadomość asynchronicznej w RabbitMQ aby użytkownik otrzymał wiadomość e-mail z powiadomieniem
  • (potencjalnie z dodatkowym kodem, ale niewiele)

Apl2 z komunikatem RabbitMQ consummer

  • wiadomości Consummes w kolejce do korespondencji w czasie rzeczywistym
  • dane Przeczytaj mail w bazie danych
  • E-mail

Problem polega na tym, że czasami App2 próbuje skonsumować wiadomość RabbitMQ zanim transakcja zostanie zatwierdzona w App1. Oznacza to, że App2 nie może odczytać danych poczty w bazie danych, ponieważ użytkownik nie został jeszcze utworzony.

Niektóre rozwiązania mogą być:

    poziom izolacji
  • Zastosowanie READ_UNCOMMITED na App2
  • Dodaj pewne opóźnienie w RabbitMQ wiadomości pocztowe (lub jakiś RetryTemplate na consummer)
  • zmienić sposób wysyłania wiadomości e-mail ...

Widziałem, że na wiosnę jest RabbitTransactionManager, ale nie mogę zrozumieć, jak to powinno wyglądać ork. Wewnętrzne aspekty obsługi transakcji zawsze wydawały się nieco trudne do zrozumienia, a dokumentacja również nie pomaga tak bardzo.


Czy istnieje sposób na zrobienie czegoś takiego?

  • Dodaj wiadomość do kolejki RabbitMQ w @Transactionnal metody
  • Po zakończeniu transakcji, wiadomość jest przyznaniem się do kolejki, a zmiany są zaangażowani w bazie
  • Tak, że wiadomość nie można skonsumować przed zakończeniem transakcji db

Jak? I czego się spodziewać na przykład, jeśli wyślę synchroniczne wiadomości RabbitMQ zamiast wiadomości asynchronicznych? Czy zablokuje wątek czekający na odpowiedź, czy coś takiego? Ponieważ wysyłamy wiadomości synchronizacji i asynchroniczne dla różnych zastosowań.

+0

mam rację, że obie aplikacje zużywają wiadomości z tej samej kolejki? – pinepain

+0

Nie, Apl1 umieścić wiadomości w kolejce i Apl2 zużywa wiadomości w tej kolejce –

+0

udało Ci się rozwiązać ten problem jakoś? Mam do czynienia z tym samym problemem. –

Odpowiedz

1

Nie jestem zaznajomiony z @Transactionnal i wiosną, ale w standardowym AMQP kolejkowanie wiadomości nie jest operacją transakcyjną, więc musisz przechowywać dane w db (jeśli połączenie db jest transakcyjne - zatwierdzić transakcję) i dopiero po tym wysłać wiadomość do brokera.

Prawidłowy obieg wygląda dla mnie jak App1: createUser -> notifyUser; App2: listenForNotifications

1

Wiem, że to późno, ale miałem ten sam problem ze względu na moją ograniczoną zrozumienia @Transactional w tym czasie. To jest bardziej dla każdego, kogo spotkasz na tym.

Kiedy użycie @Transactional aby zapisać dane do bazy danych, zapisania do bazy doesnt faktycznie zdarzyć, dopóki nie powróci metody, a nie wtedy, gdy Zapisz się nazywa.

Więc jeśli masz sposób jak

@Transactional(readOnly=false) 
public void save(Object object) { //Object should be one of your entities 
    entityManager.persist(object); //or however you have it set up 
    rabbitTemplate.convertAndSend(message); //again - however yours is 
} 

nawet pomimo nazywasz utrzymują się na obiekcie przed umieszczeniem komunikatu w kolejce, persist nie będzie faktycznie zdarzyć, dopóki nie powróci metody, tym samym powodując wiadomość, którą należy umieścić w kolejce przed zwróceniem metody i zanim dane rzeczywiście znajdą się w bazie danych.

Możliwe jest zagnieżdżanie metod @Transactional (choć nie jest to proste) może umieścić komunikat w kolejce po zwróceniu metody save(). Jednak nie można umieścić komunikatu w kolejce i oczekiwać, że nie zostanie on zużyty. Kiedy już go nie ma. Więc jeśli chcesz, opóźnij umieszczenie go w kolejce.

Jeśli chcesz otrzymać odpowiedź z kolejki w sposób synchronizowany. W moim przykładzie funkcji - możesz to zrobić, jednak będzie to trwać dłużej, zanim dane będą faktycznie przechowywane, ponieważ będzie czekał na odpowiedź od pracownika, zanim metoda będzie mogła powrócić i faktycznie utrwalić dane. (pamiętaj także, że otrzymanie odpowiedzi z kolejki ma limit czasu).

Więc moja rada to nie umieścić te 2 operacje w tym samym @Transactional