2009-06-24 17 views
7

Sto scrivendo un'applicazione .NET Windows Form che pubblicherà un messaggio in una coda MQ di Websphere e quindi eseguirà il polling di una coda diversa per una risposta. Se viene restituita una risposta, l'applicazione elaborerà parzialmente la risposta in tempo reale. Ma la risposta deve rimanere in coda in modo che un lavoro batch giornaliero, che legge anche dalla coda di risposta, possa fare il resto dell'elaborazione.Come si esplora un messaggio MQ di Websphere senza rimuoverlo?

Sono arrivato a leggere il messaggio. Quello che non sono stato in grado di capire è come leggerlo senza rimuoverlo.

Ecco cosa ho ottenuto finora. Sono un principiante MQ, quindi ogni suggerimento sarà apprezzato. E sentiti libero di rispondere in C#.

Public Function GetMessage(ByVal msgID As String) As MQMessage 
    Dim q = ConnectToResponseQueue() 
    Dim msg As New MQMessage() 
    Dim getOpts As New MQGetMessageOptions() 
    Dim runThru = Now.AddMilliseconds(CInt(ConfigurationManager.AppSettings("responseTimeoutMS"))) 
    System.Threading.Thread.Sleep(1000) 'Wait for one second before checking for the first response' 
    While True 
     Try 
      q.Get(msg, getOpts) 
      Return msg 
     Catch ex As MQException When ex.Reason = MQC.MQRC_NO_MSG_AVAILABLE 
      If Now > runThru Then Throw ex 
      System.Threading.Thread.Sleep(3000) 
     Finally 
      q.Close() 
     End Try 
    End While 
    Return Nothing 'Should never reach here' 
End Function 

NOTA: non ho verificato che il mio codice rimuove in realtà il messaggio. Ma è così che capisco che MQ funziona, e sembra che stia succedendo. Per favore correggimi se questo non è il comportamento predefinito.

+0

+1 - Vorrei aver scoperto questa domanda prima che dovessi capirlo da solo. –

risposta

11

È necessario aprire la coda con l'opzione MQOO_BROWSE. Quindi alla prima lettura fai un GET usando l'opzione MQGMO_BROWSE_FIRST. Infine, i tuoi GET successivi dovrebbero utilizzare l'opzione MQGMO_BROWSE_NEXT.

Nota: MQOO è le opzioni di apertura MQ e MQGMO è MQ Ottieni opzioni messaggio.

+0

L'ho capito. Molte grazie. –

+0

Risposta brillante. Questo mi ha salvato la pancetta oggi. Grazie. – duffymo

1

Si dovrebbe davvero fare questo con code separate. L'elaborazione di fine giornata dovrebbe avere la propria coda. Dopo aver elaborato la parte del messaggio, la si invia alla coda EOD.

Con l'opzione Sfoglia dovrai tenere traccia di quali messaggi hai già elaborato da qualche parte.

Inoltre, è possibile impostare un timeout di attesa su GET. Quindi non è necessario "attendere 1 secondo prima di controllare la coda". Come scritto in questo momento non è possibile raggiungere la condizione msg non disponibile perché non hai impostato NOWAIT nelle opzioni del messaggio get.

+0

+1 Buon punto. Non ho menzionato nel mio post che sto facendo una singola richiesta e risposta alla volta. L'ID di correlazione della risposta corrisponderà all'ID del messaggio della richiesta, quindi tenere traccia dei messaggi che ho già elaborato non dovrebbe essere un problema. Per quanto riguarda il timeout di attesa, l'avevo visto ma non avevo capito cosa farsene. Ho fatto qualche ricerca in più sulla base del tuo suggerimento e ho ripulito il metodo considerevolmente usando quell'approccio. Molte grazie! –

1

Per i posteri, ecco una (credo) versione molto migliorata del metodo basato sulle risposte di mamboking e jmucchiello.

Public Function GetMessage(ByVal correlID As Byte()) As MQMessage 
    Dim waitInterval = CInt(ConfigurationManager.AppSettings("responseTimeoutMS")) 
    Dim q As MQQueue = Nothing 
    Try 
     Dim msg As New MQMessage() 
     Dim getOpts As New MQGetMessageOptions() 
     q = ConnectToResponseQueue() 
     msg.MessageId = MQC.MQMI_NONE 
     msg.CorrelationId = correlID 
     getOpts.MatchOptions = MQC.MQMO_MATCH_CORREL_ID 
     getOpts.WaitInterval = waitInterval 
     getOpts.Options = MQC.MQGMO_BROWSE_FIRST Or MQC.MQGMO_WAIT 
     q.Get(msg, getOpts) 
     Return msg 
    Finally 
     If q IsNot Nothing AndAlso q.IsOpen() Then q.Close() 
    End Try 
End Function 
1

Mi rendo conto che sto arrivando a questa discussione un po 'tardi e probabilmente avete già codificato questa app. Nel caso in cui abbiate bisogno di modificarlo o per chiunque possa aver bisogno di fare qualcosa di simile, ho un paio di osservazioni.

Innanzitutto, se è possibile eseguire questa operazione con un client QMgr v7 e un client WMQ v7, questa sarebbe la soluzione preferita. In v7, il supporto .Net è stato spostato da un SupportPac a una parte del prodotto di base. Ci sono molte nuove funzionalità, alcune correzioni di bug e prestazioni migliori. Inoltre, su v7 puoi usare pub-sub ... che mi porta alla mia seconda osservazione.

In base alla descrizione nel post originale, l'avrei fatto in Pub-Sub. L'app che pone il messaggio ha bisogno solo di metterne una e non ha nemmeno bisogno di sapere che sta mettendo su un argomento. In realtà puoi pubblicare un alias su un argomento che lo fa apparire come una coda al produttore del messaggio. Le tue app che consumano possono quindi iscriversi o puoi effettuare due abbonamenti amministrativi in ​​modo che i messaggi pubblicati vengano indirizzati a due code che hai designato. Le tue app hanno ciascuna una coda dedicata e non sono previste modifiche alla codifica per il produttore e l'app in batch, è solo una configurazione. Ovviamente l'app che guida le transazioni dovrebbe effettivamente consumare i messaggi piuttosto che sfogliarli.

I vantaggi qui sono molteplici:

  • Come la coda si riempie di messaggi, l'indicizzazione si svuota al disco e al di sopra di una soglia si vedrà un calo di prestazioni che può essere significativo. Pertanto, il metodo attuale non scala molto bene.
  • Con il metodo pub-sub è possibile avere più istanze delle app in tempo reale o in batch o entrambe, e queste possono essere sullo stesso o diverso QMgr. Scalare è facile.
  • Elimina la dipendenza tra le app in tempo reale e in batch che devono essere sullo stesso QMgr.
  • Amministrazione più trasparente. Se vedi dei messaggi che si accumulano nella coda in tempo reale, sai che hai un problema.

Un paio di problemi completamente diversi qui pure. Uno di questi è utilizzare l'opzione Fail if Quiescing. Lo scopo di questo è che quando QMgr viene spento in modo pulito, questa opzione fa terminare la chiamata API con un codice di ritorno che indica che QMgr si sta spegnendo. Se non si include questa opzione, è possibile che con due o più app collegate QMgr effettui il mai spento in modo pulito e debba essere forzato verso il basso o che i suoi processi vengano uccisi con la forza bruta. Come regola, usa sempre Fail se Quiescing su tutte le chiamate API che lo supportano. Il motivo per cui esiste è per le persone che hanno bisogno di una transazione XA, ma per qualche motivo non possono usarlo. In questo scenario, CONNECT e la prima chiamata GET o PUT utilizza Fail se il set di Quiescing e le successive operazioni GET o PUT non lo fanno. Ciò fa in modo che QMgr attenda che l'intera serie di chiamate GET/PUT venga completata, ma successivamente il successivo CONNECT o GET/PUT utilizza Fail se Quiescing in modo che QMgr abbia la possibilità di spegnersi se necessario.

L'altra osservazione qui è che non c'è Catch nel codice qui. Immagino che ce ne sia uno di più in alto nello stack delle chiamate? È sempre consigliabile stampare il codice di ritorno WMQ da un'eccezione in modo da poter rintracciare la causa principale. Per quanto riguarda gli incarichi di consulenza, consiglio sempre ai clienti che la mancata stampa del codice di ritorno (o l'eccezione collegata per il codice JMS/XMS) è un ostacolo che dovrebbe impedire la promozione di un'app alla produzione. È davvero così importante. Anche se hai un codice nel codice che richiama getMessage(), qualcuno che riutilizzando qui lo snippet di codice di esempio potrebbe non rendersi conto che manca questo pezzo importante.

Problemi correlati