2012-03-02 17 views
7

Quello che sto per descrivere è essenzialmente un problema di commit in due fasi tra due sistemi diversi e sto cercando consigli su come gestirlo. Nella nostra applicazione web, scarichiamo alcune costose operazioni di terze parti, come l'invio di e-mail, a processi out-of-band in background (la chiamiamo infrastruttura di lavoro)Impegno a due fasi - Come utilizzare la mia coda in modo efficace?

Per inviare un'email, ad esempio, creiamo sia un oggetto email che un lavoro di posta elettronica nel nostro database. Dovremo quindi attendere che il nostro monitor del lavoro prelevi il lavoro di posta elettronica e lo invii. Il monitoraggio del lavoro funziona essenzialmente eseguendo il polling del database ogni pochi secondi quando è inattivo.

Questo, tuttavia, aggiunge un ritardo nell'invio di e-mail e aggiunge quello che vedo come carico indebito sul database con il polling. Sarebbe molto più bello se potessimo mettere immediatamente il lavoro di posta elettronica in coda non appena verrà creata l'email.

Tuttavia, ciò non riesce attualmente per due motivi. Innanzitutto, la coda è spesso molto più veloce della richiesta web. L'e-mail viene prelevata per l'elaborazione prima che la richiesta Web abbia impegnato la sua transazione di database, quindi non può generare correttamente l'e-mail. In secondo luogo, se la richiesta web non riesce, ripristina la transazione del database, il che significa che l'email deve essere non inviata. Tuttavia, se è già stato messo in coda, non è più nel controllo della richiesta.

Esiste una buona strategia per la creazione di un commit a due fasi tra la coda e il database? Per riferimento, stiamo usando RabbitMQ e MySQL con le tabelle InnoDB. Un'idea che avevo in testa era di incollare i lavori di posta elettronica in coda dopo che la transazione del database è stata commessa, ma ciò lascia la possibilità che l'e-mail non venga mai messa in coda. Dovrò ancora creare un processo di polling per le e-mail che avrebbero dovuto essere inviate e non lo erano.

risposta

0

Mi rendo conto che questo è un paio di anni in ritardo :) ma volevo aggiungere qualche riflessione su questo per gli altri che rispondono a questa domanda.

È possibile inviare il messaggio in ritardo per aumentare la possibilità che il DB sia pronto quando il lavoro lo ottiene. Non ho mai usato RabbitMQ ma ho trovato questo esempio di utilizzo di una coda rabbitMQ come coda ritardata How to create a delayed queue in RabbitMQ?. Il tuo lavoro di posta elettronica dovrebbe comunque occuparsi di record non commentati poiché il ritardo non è un metodo deterministico per gestire l'elaborazione distribuita.

Detto questo, sembra che ci sia spazio per migliorare il tuo design. Generalmente con le architetture di servizio è una cattiva idea condividere tabelle db tra servizi. Porta a problemi distribuiti di scalabilità e transazioni. Vorrei provare ad assicurare che il messaggio RabbitMQ contenga tutti i dati necessari per elaborare l'e-mail indipendentemente da qualsiasi altro servizio. O se ha bisogno di più dati, dovrebbe richiedere tali dati attraverso una richiesta di ServiceBus anziché una query del DB.