2013-07-02 22 views
10

Per semplificare il mio problema, hoPrimavera/RabbitMQ: gestione delle transazioni

App1 con il metodo createUser @Transactionnal():

  • Inserisci nuovo utente nel database
  • Aggiungi messaggio asincrona in RabbitMQ in modo che l'utente riceva una mail di notifica
  • (potenzialmente qualche codice aggiuntivo, ma non molto)

App2 con il messaggio RabbitMQ consummer

  • messaggi Consummes sulla coda mailing in tempo reale
  • dati leggere la posta in database
  • Invia posta

Il problema è che a volte, App2 tenta di consumare il messaggio RabbitMQ prima che la transazione venga eseguita su App1. Ciò significa che App2 non può leggere i dati della posta sul database perché l'utente non è ancora stato creato.

Alcune soluzioni possono essere:

  • Usa READ_UNCOMMITED livello di isolamento su App2
  • Aggiungi un po 'di ritardo nella RabbitMQ messaggi di consegna (o qualche RetryTemplate sul consummer)
  • Cambiare il nostro modo di inviare messaggi di posta elettronica ...

Ho visto che c'è un RabbitTransactionManager in primavera, ma non riesco a capire come dovrebbe ork. Gli interni di materiale per la gestione delle transazioni sembrano essere sempre un po 'difficili da capire e anche la documentazione non aiuta molto.


C'è un modo per fare qualcosa del genere?

  • Aggiungere un messaggio a una coda RabbitMQ in un metodo @Transactionnal
  • Quando si conclude la transazione, il messaggio si impegna a coda, e le modifiche vengono commessi al database
  • modo che il messaggio non può essere consumato prima che la transazione db termini

Come? E cosa aspettarsi per esempio se invio messaggi RabbitMQ sincroni invece di messaggi asincroni? Bloccherebbe il thread in attesa di una risposta o qualcosa del genere? Perché inviamo messaggi di sincronizzazione e asincroni per diversi casi di utilizzo.

+0

ho ragione che entrambe le applicazioni consumare messaggi dalla stessa coda? – pinepain

+0

No, App1 inserisce i messaggi in una coda e App2 consuma messaggi in quella coda –

+0

Sei riuscito a risolvere questo problema in qualche modo? Sto affrontando lo stesso problema. –

risposta

1

Non ho familiarità con @Transactionnal e molla, ma in AMQP l'accodamento dei messaggi standard non è un'operazione transazionale, quindi è necessario memorizzare i dati in db (se la connessione db è transazionale - transazione di commit) e solo dopo tale invio messaggio al broker.

la correttezza del flusso di lavoro sembra per me come App1: createUser -> notifyUser; App2: listenForNotifications

1

So che questo è in ritardo ma ho avuto lo stesso problema a causa della mia limitata comprensione @Transactional al momento. Quindi questo è più per chiunque altro ti capita di imbattersi in questo.

Quando si utilizza @Transactional per salvare i dati nel database, il salvataggio nel database non si verifica effettivamente fino a quando il metodo non ritorna, e non quando viene richiamato il salvataggio.

Quindi, se si dispone di un metodo come

@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 
} 

anche tho si chiama il persistono sull'oggetto prima di mettere il messaggio nella coda, il persistono non sarà effettivamente accadere fino a quando il metodo restituisce, provocando in tal modo la messaggio da mettere in coda prima che il metodo ritorni e prima che i dati siano effettivamente nel database.

È possibile annidare i metodi @Transactional (che non è diretto) può mettere il messaggio in coda dopo il ritorno del metodo save(). Tuttavia non è possibile inserire il messaggio in coda e aspettarsi che non venga consumato. Una volta che è andato via. Quindi, rimettilo in coda se è necessario.

Se si desidera ricevere una risposta dalla coda in modo sincrono. Nel mio esempio di funzione, puoi farlo, ma ci vorrà solo più tempo per perseguire realmente i dati, poiché sarà in attesa della risposta da parte del lavoratore prima che il metodo possa tornare e in effetti mantenere i dati. (ricorda anche che ricevere una risposta da un messaggio in coda ha un timeout).

Quindi il mio consiglio è quello di non mettere quei 2 operazioni nella stessa @Transactional

Problemi correlati