2015-06-18 20 views
13

Sto usando RabbitMQ in C# con la libreria EasyNetQ. Sto usando un modello pub/sub qui. Ho ancora alcuni problemi che spero qualcuno possa aiutarmi con:Come gestire gli errori con EasyNetQ/RabbitMQ

  1. Quando si verifica un errore durante il consumo di un messaggio, questo viene automaticamente spostato in una coda di errore. Come posso implementare i tentativi (in modo che vengano reinseriti nella coda di origine e quando non riesce a elaborare X volte, viene spostato su una coda di messaggi non recapitati)?
  2. Per quanto posso vedere c'è sempre 1 coda di errore che viene utilizzata per scaricare i messaggi da tutte le altre code. Come posso avere 1 coda di errore per tipo, in modo che ogni coda abbia la sua coda di errore associata?
  3. Come posso riprovare facilmente i messaggi che si trovano in una coda errori? Ho provato Hosepipe, ma è in grado di ripubblicare i messaggi nella coda degli errori anziché nella coda di origine. Non mi piace molto questa opzione perché non voglio essere in giro in una console. Preferibilmente vorrei solo programmare contro la coda degli errori.

Chiunque?

risposta

10

Il problema che si sta verificando con EasyNetQ/RabbitMQ è che è molto più "crudo" rispetto ad altri servizi di messaggistica come SQS o Azure Service Bus/Queues, ma farò del mio meglio per indicarti il ​​giusto direzione.

Domanda 1.

Questo sarà su di voi per fare. Il modo più semplice è che puoi No-Ack un messaggio in RabbitMQ/EasyNetQ, e sarà posto in testa alla coda per riprovare. Ciò non è consigliabile in quanto verrà ritentato quasi immediatamente (senza ritardi) e bloccherà anche altri messaggi dall'elaborazione (se si dispone di un solo utente con un numero di prefetch pari a 1).

Ho visto altre implementazioni dell'utilizzo di "MessageEnvelope". Quindi una classe wrapper che quando un messaggio fallisce, si incrementa una variabile retry sul MessageEnvelope e si riconsegna nuovamente il messaggio alla coda. Dovresti farlo e scrivere il codice di avvolgimento attorno ai tuoi gestori di messaggi, non sarebbe una funzione di EasyNetQ.

Utilizzando quanto sopra, ho anche visto persone usare le buste, ma lasciare che il messaggio sia morto. Una volta nella coda delle lettere morte, c'è un'altra applicazione/lavoratore che legge gli elementi dalla coda delle lettere morte.

Tutti questi approcci sopra hanno un piccolo problema in quanto non c'è un modo veramente carino di avere un ritardo logaritmico/esponenziale/qualsiasi di ritardo nell'elaborazione del messaggio. Puoi "tenere" il messaggio in codice per un po 'di tempo prima di restituirlo alla coda, ma non è un bel modo.

Tra tutte queste opzioni, la propria applicazione personalizzata che legge la coda di messaggi non recapitabili e decidere se reindirizzare il messaggio in base a una busta contenente il numero di tentativi è probabilmente la migliore.

Domanda 2.

È possibile specificare uno scambio di lettera morta per coda utilizzando l'API avanzate. (https://github.com/EasyNetQ/EasyNetQ/wiki/The-Advanced-API#declaring-queues). Tuttavia, ciò significa che dovrai utilizzare l'API avanzata praticamente ovunque, poiché l'utilizzo della semplice implementazione IBus di subscribe/publish cerca le code che vengono denominate in base al tipo di messaggio e al nome del sottoscrittore.L'uso di una dichiarazione di coda personalizzata significa che dovrai gestire personalmente la denominazione delle code, il che significa che quando ti iscrivi, dovrai conoscere il nome di ciò che vuoi ecc. Non più iscrizioni automatiche per te!

Domanda 3

Un errore coda/Dead Letter Queue è solo un'altra coda. Puoi ascoltare questa coda e fare ciò che devi fare con essa. Ma non c'è davvero nessuna soluzione pronta per l'uso che suoni come si adatterebbe alle tue esigenze.

+0

Abbiamo trovato che non c'era davvero alcun uso pratico per l'implementazione standard di EasyNetQ al di fuori di una singola dimostrazione rapida, legata ad alcune classi .NET condivise, per gli utenti principianti. "API Sì, puoi fare cose avanzate, ma onestamente è un'API meravigliosamente semplice da usare, sicuramente un fan dell'API di Easy's Advanced per qualsiasi tipo di lavoro –

5

Ho implementato esattamente ciò che descrivi. Ecco alcuni suggerimenti basati sulla mia esperienza e relativi a ciascuna delle tue domande.

Q1 (come riprovare X volte):

Per questo, è possibile utilizzare IMessage.Body.BasicProperties.Headers. Quando si consuma un messaggio da una coda di errori, basta aggiungere un'intestazione con un nome scelto. Cerca questa intestazione su ogni messaggio che entra nella coda degli errori e incrementalo. Questo ti darà un conteggio dei tentativi in ​​corso.

È molto importante che si dispone di una strategia per cosa fare quando un messaggio supera il limite di tentativi di X. Non si vuole perdere quel messaggio. Nel mio caso, scrivo il messaggio su disco a quel punto. Ti offre molte utili informazioni di debug per tornare più tardi, perché EasyNetQ esegue automaticamente il wrapping del messaggio di origine con le informazioni di errore. Ha anche il messaggio originale, in modo che tu possa, se vuoi, manualmente (o magari automatizzato, tramite un codice di rielaborazione batch), ri-accodare il messaggio in un secondo momento in modo controllato.

Puoi vedere il codice nell'utilità Hosepipe per vedere un buon modo per farlo. In effetti, se segui lo schema che vedi lì, puoi anche utilizzare Hosepipe in seguito per riaccodare i messaggi se necessario.

Q2 (come creare una coda di errore per coda originario):

È possibile utilizzare l'EasyNetQ avanzata Bus per fare questo in modo pulito. Utilizzare IBus.Advanced.Container.Resolve<IConventions> per accedere all'interfaccia delle convenzioni. Quindi è possibile impostare le convenzioni per la denominazione della coda di errore con conventions.ErrorExchangeNamingConvention e conventions.ErrorQueueNamingConvention. Nel mio caso, ho impostato la convenzione in base al nome della coda di origine in modo da ottenere una coppia di code/queue_error di code ogni volta che creo una coda.

Q3 (come elaborare i messaggi nelle code di errore):

È possibile dichiarare un consumatore per l'errore coda allo stesso modo di fare qualsiasi altra coda. Anche in questo caso, AdvancedBus ti consente di farlo in modo pulito specificando che il tipo che si stacca dalla coda è EasyNetQ.SystemMessage.Error. Quindi, IAdvancedBus.Consume<EasyNetQ.SystemMessage.Error>() ti porterà lì. Riprendere significa semplicemente ripubblicare allo scambio originale (prestando attenzione al numero di tentativi che hai inserito nell'intestazione (vedi la mia risposta al Q1, sopra), e le informazioni nel messaggio di errore che hai consumato dalla coda degli errori possono aiutarti a trovare l'obiettivo per

+0

Qualche possibilità di avere un esempio funzionante? –

+0

Ho funzionato, vedere l'esempio qui http://stackoverflow.com/questions/32077044/re-queue-message-on-exception –

Problemi correlati