2010-08-09 9 views
9

Ich habe einen JMS-Client, der nach Empfang einer Nachricht ssh Remote-Systemen kann (und verschiedene Dinge dort tun - nicht relevant für die Frage). Es ist möglich, dass Hunderte solcher Nachrichten in einer kurzen Zeitspanne ankommen, die SOFORT verarbeitet werden muss.JMS-Nachricht Re-Delivery-Verzögerung

Es ist jedoch auch möglich, dass bestimmte entfernte Systeme nicht verfügbar sind, wenn die Nachricht empfangen wird, daher sollten sie auf später verschoben werden (z. B. 1 Stunde oder so). Die beste Lösung wäre es, die Nachricht mit einem gewissen "Verzögerungs" -Wert zurück in die Warteschlange zu stellen, was dem JMS-Broker sagt, dass er nicht versuchen soll, die Nachricht innerhalb einer Stunde erneut zuzustellen.

Was ist nicht OK: Schlaf im Empfangsfaden und wache eine Stunde später auf. Da der Nachrichtenverbraucherpool begrenzt ist (z. B. 8 verfügbare Verbindungen) mit 8 nicht erreichbaren Systemen würde die gesamte Verarbeitung unnötig blockieren, was inakzeptabel ist.

Ich habe keine Einstellung für die Nachricht oder die Warteschlange selbst für einen solchen "Verzögerung" -Wert gefunden, existiert es?

Eine Problemumgehung Lösung besteht darin, eine zweite Warteschlange zu dem Speichern von Nachrichten zu unerreichbaren Systemen zu verwenden, und diese separat zu verarbeiten. Aber es ist keine sehr elegante Lösung und erfordert zusätzliche Programmierung. Vielleicht gibt es einen besseren Weg.

Antwort

3

Dies ist nicht über die JMS-API vor JMS 2.0 möglich. In der Regel werden Nachrichtentransporte optimiert, um Nachrichten so schnell wie möglich zuzustellen, und es fehlen Scheduler, die eine Nachricht für die erneute Zustellung in einem beliebigen Intervall halten. Angenommen, es gibt einen Transportanbieter, der über diese Funktionalität verfügt, wäre alles, was Sie schreiben, an diesen Transportanbieter gebunden, denn obwohl der Code JMS-kompatibel ist, würde sich die App selbst auf dieses herstellerspezifische Verhalten stützen.

Weitere Informationen finden Sie in der Antwort von @ Shashi auf eine Antwort, die für Versionen von MQ gilt, die JMS 2.0 unterstützen.

+0

Das ist eine informative Antwort, danke. – egbokul

+1

Ich nehme an, das war nur für JMS 1.0 wahr? (Vgl. Shashis Antwort) – jpaugh

+1

Yup. Die neuen MQ JMS-Klassen unterstützen die verzögerte Zustellung. –

4

In diesem Fall werden Container Managed Transactions verwendet. Die Transaktion wird gestartet, wenn die Methode onMessage vom Container aufgerufen wird und festgeschrieben wird, wenn die Methode onMessage erfolgreich beendet wurde (sie schlägt fehl, wenn eine RuntimeException ausgelöst wird oder setRollBackOnly aus dem MessageDrivenBean-Kontext aufgerufen wird). Sie können auch das Redelivery-Intervall und die maximale Anzahl der erneuten Zustellungen konfigurieren.

Wenn Sie OpenMQ mit Glassfish-Server verwenden, können Sie dies im Deskriptor ejb-jar.xml konfigurieren. Stellen Sie im Deskriptor ejb-jar.xml die Eigenschaften endpointExceptionRedeliveryInterval (in Millisekunden) und endpointExceptionRedeliveryAttempts (Anzahl der erneuten Zustellungen der Nachricht vor dem Senden an die Warteschlange für unzustellbare Nachrichten) ein. Hier ein Beispiel:

<?xml version="1.0" encoding="UTF-8"?> 
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" 
    version="3.1">  
    <enterprise-beans> 
     <message-driven> 
      <ejb-name>EjbName</ejb-name> 
      <ejb-class>com.example.MyMessageDrivenBean</ejb-class> 
      <messaging-type>javax.jms.MessageListener</messaging-type> 
      <transaction-type>Container</transaction-type> 
      <activation-config> 
       <activation-config-property> 
        <activation-config-property-name>destination</activation-config-property-name> 
        <activation-config-property-value>someQueue</activation-config-property-value> 
       </activation-config-property> 
       <activation-config-property> 
        <activation-config-property-name>destinationType</activation-config-property-name> 
        <activation-config-property-value>javax.jms.Queue</activation-config-property-value> 
       </activation-config-property> 

       <activation-config-property> 
        <activation-config-property-name>endpointExceptionRedeliveryInterval</activation-config-property-name> 
        <activation-config-property-value>5000</activation-config-property-value> 
       </activation-config-property> 
       <activation-config-property> 
        <activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name> 
        <activation-config-property-value>4</activation-config-property-value> 
       </activation-config-property> 
      </activation-config> 
     </message-driven> 
    </enterprise-beans> 
</ejb-jar> 

Und in der Nachricht Driven Bean eine Runtime werfen sie markieren als nicht bestanden und die Nachricht wird in die Warteschlange zurückgeschickt werden.

Hier sind auch die Konfigurationseigenschaften für WebLogic Server: http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/pagehelp/JMSjmstemplatesjmstemplateconfigredeliverytitle.html

+0

Die sun-ejb.jar.xml kann ebenfalls verwendet werden. https://docs.oracle.com/cd/E19798-01/821-1750/beaqm/index.html – 99Sono

0

ich auf das Problem aussehen würde wie: jms Nachricht Verbraucher Pool zur Verfügung ... während einige Back-End-Ressourcen (zB ssh) nicht verfügbar um die Fertigstellung der Nachricht zu ermöglichen.

Wenn Sie damit einverstanden sind, dann wird das Problem, warum ist der Consumer-Pool verfügbar, da er den Verbrauch nicht vollenden kann? Hätten Sie den Pool nicht zur Verfügung, dann stapeln sich die Nachrichten in der Warteschlange .... bis zur Verfügung ...und das hätte in Ordnung sein können, wenn verfügbar. Wenn das der Fall ist, brauchen Sie nur eine Überwachungskomponente, um den Pool zu starten/stoppen, abhängig davon, ob Ressourcen verfügbar sind. Sie müssen nicht 1 Stunde warten, aber solange das Backend nicht verfügbar ist. am Ende jms ist alles, aber kein Überwachungswerkzeug.

9

JMS 2.0 Spezifikation definiert eine "Delivery Delay", wobei der Client einen Zustellungsverzögerungswert in Millisekunden für jede Nachricht angeben kann, die er sendet. Dieser Wert definiert eine Nachrichtenübermittlungszeit, die die Summe der Zustellungsverzögerung der Nachricht und der GMT ist, die sie sendet (für transaktionsgebundene Nachrichten ist dies die Zeit, zu der der Client die Nachricht sendet, nicht die Zeit, zu der die Transaktion festgeschrieben wird).

Die Lieferzeit einer Nachricht ist der früheste Zeitpunkt, zu dem ein JMS-Provider die Nachricht am Zielziel sichtbar machen und für die Zustellung an die Kunden verfügbar machen kann. Der Anbieter darf keine Nachrichten liefern, bevor die Lieferzeit erreicht ist.

Diese Funktion ist ziemlich praktisch für das oben beschriebene Szenario.

0

Auf Glassfischen können die folgenden Referenzen von Nutzen sein.

https://docs.oracle.com/cd/E19798-01/821-1794/aeooq/index.html

Auf der oben genannten Referenz Sie eine Liste der Aktivierungseigenschaften erhalten, die von Glasfischen unterstützt werden. Zum Beispiel endpointExceptionRedeliveryAttempts -
Anzahl, wie oft eine Nachricht erneut zuzustellen, wenn MDB eine Ausnahme während die Nachrichtenübermittlung wirft

Dann haben Sie die folgende Referenz, die Elemente gültige XML beschreibt auf der Sonnen-ejb-jar.xml zu verwenden, die durch unterstützt wird Glasfische. https://docs.oracle.com/cd/E19798-01/821-1750/beaqm/index.html

Schließlich könnten Sie einen Mdb konfigurieren, wie im folgenden Ausschnitt dargestellt.

<ejb> 
    <ejb-name>MyMdbWith0MsRedeliveryDelayAndMultipleRedeliveriesMdb</ejb-name> 
    <bean-pool> 
     <steady-pool-size>1</steady-pool-size> 
     <resize-quantity>1</resize-quantity> 
     <max-pool-size>1</max-pool-size> 
    </bean-pool> 
    <mdb-resource-adapter> 
     <activation-config> 
      <activation-config-property> 
       <activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name> 
       <activation-config-property-value>1000</activation-config-property-value> 
      </activation-config-property> 
      <activation-config-property> 
       <activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name> 
       <activation-config-property-value>0</activation-config-property-value> 
      </activation-config-property> 
     </activation-config>    
    </mdb-resource-adapter> 
</ejb> 

sollte sichergestellt werden, dass für diese besondere mdb, Glassfish eine Nachricht sofort liefern und, wenn sie es sofort wird es erneut versuchen fehlschlägt.

Erstellen Sie in Ihrem WAR-Projekt eine Sub-ejb-jar.xml, und legen Sie sie unter WEB-INF/sun-ejb-jar.xml ab.

Wenn Sie Maven verwenden, wäre dies der Pfad src/main/webapp/WEB-INF/sub-ejb-jar.xml in der Kriegsprojektkomponente.