2013-02-27 16 views
6

Ho più applicazioni esistenti che inviano e ricevono messaggi utilizzando MSMQ tramite l'API System.Messaging. Le code sono generalmente non transazionali e sono una combinazione di MSMQ 3 e 4.Creazione di un meccanismo tentativi in ​​MSMQ senza WCF

Le applicazioni di ricezione gestiscono i messaggi poison ora nella misura in cui alla prima occorrenza di qualsiasi eccezione i messaggi vengono messi su una coda di errore per l'intervento manuale . Ma si scopre che la stragrande maggioranza dell'intervento manuale consiste semplicemente nel riportare il messaggio alla coda principale per un altro tentativo, a quel punto riesce. Quindi, per automatizzare tale processo, voglio aggiungere una funzione di riprova al destinatario in modo tale che i messaggi vengano spostati nella coda principale un determinato numero di volte con un determinato ritardo tra ciascuno.

Piuttosto che reinventare la ruota, voglio sfruttare tutto ciò che MSMQ fornisce fuori dalla scatola così come tutti i modelli popolari o di migliori pratiche intorno a questo. A tal fine, c'è molto altro sul supporto aggiuntivo per i messaggi velenosi in MSMQ 4. Ma non sembrano essere facilmente accessibili tramite .Net. Inoltre, gli unici riferimenti che posso trovare per usarli sono tramite WCF con un bind MSMQ.

Qualcuno può suggerire qualche schema o indicare qualsiasi esempio che implementa un nuovo tentativo se non si sta utilizzando WCF?

risposta

7

Non sono riuscito a trovare uno schema unico e popolare per farlo. Ma dopo aver spiato un po 'in System.Messaging, sono stato in grado di sfruttare le proprietà dei messaggi e il comportamento MSMQ in quello che penso fosse un modo appropriato per portare a termine il lavoro con un minimo di parti mobili.

Ecco cosa ho implementato.Si è scoperto essere abbastanza semplice e leggero - non molto codice e di facile manutenzione:

ho creato un oggetto chiamato RetryLevel che ha tre proprietà:

int dell'Ordine, Int NumberOfRetries, TimeSpan ritardo

La configurazione dell'applicazione ricevente ora ha un elenco di RetryLevel. Quindi la nuova funzionalità supporta sostanzialmente i tentativi di livello n.

Quindi ho creato un oggetto chiamato RetryInfo. Questo oggetto ha due proprietà:

int tentativi, stringa SourceQueuePath

un'istanza dell'oggetto RetryInfo è serializzato e memorizzato nella proprietà di estensione di ciascun messaggio che finisce per essere ritentato. Ciò mi consente di tenere traccia dello stato corrente dei tentativi sul messaggio stesso, eliminando così la necessità di mantenere un separato archivio dei metadati e tutto il sovraccarico di riconciliazione degli ID dei messaggi, mantenendo i dati sincronizzati, ecc.

Infine, ho aggiunto un percorso di attesa in coda alla configurazione del ricevitore. Questa coda è dove i messaggi verranno eliminati mentre sono in "timeout".

Così ora, quando un gestore di messaggi rifiuta un messaggio, il ricevitore deserializza è RetryInfo, se ce n'è uno, e guarda il numero di (precedenti) tentativi per determinare quale dei RetryLevel configurati ha raggiunto.

Il ricevitore imposta quindi la proprietà TimeToBeRecieved (TTBR) del messaggio su DateTime.Ora più il valore Ritardo del RetryLevel appropriato. Quindi imposta la proprietà AdministrativeQueue su una coda creata dalla proprietà SourceQueuePath di RetryInfo e imposta AcknowledgeType del messaggio su AcknowledgeTypes.NegativeReceive. Alla fine mette il messaggio nella coda di attesa.

Da qui, MSMQ controlla il messaggio TTBR del messaggio. Quando è scaduto, MSMQ rimette il messaggio in coda nella sua proprietà AdministrativeQueue, che è la coda originariamente originata dal messaggio. Se il messaggio continua a essere rifiutato dai gestori, si sposta semplicemente su RetryLevels.

Se Tentativi di un messaggio è oltre quello di tutti i NumberOfRetries sui RetryLevels configurati, la proprietà TTBR del messaggio è impostata su TimeSpan.Zero, la proprietà UseDeadLetterQueue è impostata su true e il messaggio viene inserito nella coda di attesa proprio come qualsiasi altro tentativo. Questa volta, tuttavia, si interrompe immediatamente e MSMQ lo invia alla coda di messaggi non recapitati (DLQ) di sistema della coda di attesa in cui può essere gestita manualmente.

0

Come dici tu non vuoi re-inventare la ruota, ti suggerisco di usare uno dei molti framework disponibili come MassTransit o altri.

Personalmente, ho fatto esperienza positiva con NServiceBus, che si trova in cima a MSMQ.

Consente di configurare la gestione degli errori in modo semplice. È possibile definire la coda di lavoro effettiva per l'applicazione e definire in modo definitivo una coda di errore dedicata. Inoltre, si configurano quanti tentativi l'applicazione - automaticamente e completamente trasparente per il codice - tenterà fino a quando non sposta il messaggio veleno nella coda di propria scelta.

Questo permette di configurare facilmente qualcosa come: "Se non posso elaborare questo messaggio correttamente entro 5 tentativi, poi spostarlo nella mia coda di errore"

Si tratta di un out-of-the-box funzionalità.

Esempio di configurazione (da documentazione ufficiale), si noti il ​​app.config della parte Editore:

Basic Publisher/Subscriber configuration from official documentation http://images.nservicebus.com/basic_pubsub.png

Per quanto riguarda la parte non-WCF, NServiceBus funziona altrettanto bene per qualsiasi applicazione .NET. Hai la possibilità di fare semplicemente riferimento alle DLL oppure puoi utilizzare NServiceBus come contenitore per ospitare la tua applicazione come servizio locale, oppure puoi registrarlo definitivamente come servizio di Windows. E infine, se un giorno vorresti cambiare idea, passerai a WCF che sarebbe supportato anche tu. :-)

+0

Grazie Jens. Sono a conoscenza di NServiceBus e MassTransit che sono, come WCF, le applicazioni basate su MSMQ con funzionalità di retry. Ma la mia domanda è quale sia un buon modo per creare nuove funzionalità se si sta costruendo un'applicazione su MSMQ. Non è il modo migliore per sostituire la mia applicazione con un'altra. –

Problemi correlati