Wiederverbindungslogik in einer Java EE -Anwendung implementieren

Enterprise JavaBeans und webbasierte Anwendungen, deren Verbindung bei Ausfall eines Warteschlangenmanagers automatisch wiederhergestellt werden soll, müssen ihre eigene Verbindungswiederholungslogik implementieren.

Nachfolgend erhalten Sie weitere Informationen, wie dies erreichbar ist.

Anwendungsfehler zulassen

Für diese Vorgehensweise sind keine Anwendungsänderungen erforderlich, jedoch eine administrative Rekonfiguration der Verbindungsfactory-Definition, um dieser die Eigenschaft CONNECTIONNAMELIST hinzuzufügen. Das aufrufende Programm muss jedoch in der Lage sein, einen Ausfall entsprechend zu handhaben. Beachten Sie aber, dass dies auch auf Fehler wie MQRC_Q_FULL zutrifft, die nichts mit Verbindungsfehlern zu tun haben.

Beispielcode für diesen Vorgang:
public class SimpleServlet extends HttpServlet {   
  public void doGet(HttpServletRequest request,                      
                    HttpServletResponse response)     
       throws ServletException, IOException {     
          try {      
 // get connection factory/ queue       
 InitialContext ic = new InitialContext();       
 ConnectionFactory cf =                 
           (ConnectionFactory)ic.lookup("java:comp/env/jms/WMQCF");  
 Queue q = (Queue) ic.lookup("java:comp/env/jms/WMQQueue");       

 // send a message       
 Connection c = cf.createConnection();  
 Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);  
 MessageProducer p = s.createProducer(q);    
 Message m = s.createTextMessage();  
 p.send(m); 

 // done, release the connection 
 c.close();
 }
 catch (JMSException je) {  
 // process exception 
   } 
 } 
}

Im vorangegangenen Codebeispiel wird davon ausgegangen, dass für die vom Servlet verwendete Verbindungsfactory die Eigenschaft CONNECTIONNAMELIST definiert ist.

Wenn das Servlet zum ersten Mal verarbeitet wird, wird mit der Eigenschaft CONNECTIONNAMELIST eine neue Verbindung erstellt, wobei davon ausgegangen wird, dass keine gepoolten Verbindungen von anderen Anwendungen verfügbar sind, die eine Verbindung zu demselben Warteschlangenmanager herstellen.

Nach der durch einen close()-Aufruf initiierten Verbindungsfreigabe wird diese Verbindung wieder in den Pool zurückgestellt und bei der nächsten Ausführung des Servlets - ohne Bezug auf die Eigenschaft CONNECTIONNAMELIST - wiederverwendet. Dies gilt bis zu einem Verbindungsfehler, in welchem Fall ein CONNECTION_ERROR_OCCURRED-Ereignis generiert wird. Durch dieses Ereignis wird der Pool aufgefordert, die fehlerhafte Verbindung zu vernichten.

Bei der nächsten Ausführung des Servlets steht nun keine gepoolte Verbindung mehr zur Verfügung. Daher wird wieder auf die Eigenschaft CONNECTIONNAMELIST zurückgegriffen, um eine Verbindung mit dem ersten verfügbaren Warteschlangenmanager herzustellen. Bei einem Warteschlangenmanager-Failover (wenn es sich beispielsweise nicht um einen vorübergehenden Netzausfall handelte), stellt das Servlet eine Verbindung mit der Backup-Instanz her, sofern eine solche verfügbar ist.

Sind an der Anwendung auch andere Ressourcen beteiligt, beispielsweise Datenbanken, ist eventuell die Instruktion erforderlich, dass der Anwendungsserver die Transaktion durch ein Rollback zurücksetzen muss.

Verbindungswiederherstellung innerhalb der Anwendung regeln

Wenn das aufrufende Programm einen Fehler des Servlets nicht verarbeiten kann, muss die Verbindungswiederherstellung innerhalb der Anwendung geregelt werden. Wie im folgenden Beispiel gezeigt, muss die Anwendung zum Verarbeiten einer Verbindungswiederholung innerhalb der Anwendung eine neue Verbindung anfordern, damit sie die Verbindungsfactory, die sie über JNDI gesucht hat, in den Cache stellen und eine JMSException wie JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').
public void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 

  // get connection factory/ queue 
  InitialContext ic = new InitialContext(); 
  ConnectionFactory cf = (ConnectionFactory) 
               ic.lookup("java:comp/env/jms/WMQCF"); 
  Destination destination = (Destination) ic.lookup("java:comp/env/jms/WMQQueue"); 

  setupResources(); 
  
  // loop sending messages 
  while (!sendComplete) { 
    try { 
      // create the next message to send 
      msg.setText("message sent at "+new Date()); 
      // and send it 
      producer.send(msg); 
    } 
    catch (JMSException je) { 
        // drive reconnection 
        setupResources(); 
    } 
  } 
Im folgenden Beispiel erstellt setupResources() die JMS -Objekte und schließt eine Ruhemodus-und Wiederholungsschleife ein, um die nicht sofortige Verbindungswiederholung zu verarbeiten. In der Praxis können dadurch sehr viele Verbindungswiederherstellungsversuche vermieden werden. Beachten Sie, dass in diesem Beispiel Exit-Bedingungen weggelassen wurden, um den Code so einfach wie möglich darzustellen.
 private void setupResources() { 

    boolean connected = false; 
    while (!connected) { 
      try { 
        connection = cf.createConnection(); // cf cached from JNDI lookup 
        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
        msg = session.createTextMessage(); 
        producer = session.createProducer(destination); // destination cached from JNDI lookup 
        // no exception? then we connected ok 
        connected = true; 
      } 
      catch (JMSException je) { 
        // sleep and then have another attempt 
        try {Thread.sleep(30*1000);} catch (InterruptedException ie) {} 
      } 
    } 

Wenn die Anwendung die Verbindungswiederherstellung verwaltet, ist es wichtig, dass die Anwendung alle Verbindungen freigibt, die für andere Ressourcen gehalten werden, unabhängig davon, ob es sich bei diesen Ressourcen um andere IBM® MQ -Warteschlangenmanager oder andere Back-End-Services wie Datenbanken handelt. Sie müssen diese Verbindungen wiederherstellen, wenn die Verbindung zu einer neuen ' IBM MQ hergestellt ist. Andernfalls bleiben Anwendungsserverressourcen für die Dauer des Verbindungswiederherstellungsversuchs unnötig gesperrt und haben zu dem Zeitpunkt, zu dem sie schließlich verwendet werden können, eventuell bereits ihr Zeitlimit erreicht.

WorkManager verwenden

Für langlebige Anwendungen (z. B. Stapelverarbeitung), bei denen die Verarbeitungszeit einige zehn Sekunden überschreitet, kann der WebSphere® Application Server WorkManager verwendet werden. Es folgt ein Beispiel für ein Codefragment für " WebSphere Application Server:
public class BatchSenderServlet extends HttpServlet  { 
  
  private WorkManager workManager = null; 
  private MessageSender sender; // background sender WorkImpl 
  
  public void init() throws ServletException { 
    InitialContext ctx = new InitialContext(); 
    workManager = (WorkManager)ctx.lookup(java:comp/env/wm/default); 
    sender = new MessageSender(5000); 
    workManager.startWork(sender); 
  } 

  public void destroy() { 
    sender.halt(); 
  } 

  public void doGet(HttpServletRequest req, HttpServletResponse res) 
                               throws ServletException, IOException { 
    res.setContentType("text/plain"); 
    PrintWriter out = res.getWriter(); 
    if (sender.isRunning()) { 
      out.println(sender.getStatus()); 
    } 
} 
Dabei enthält die Datei web.xml Folgendes:
<resource-ref> 
      <description>WorkManager</description> 
      <res-ref-name>wm/default</res-ref-name> 
      <res-type>com.ibm.websphere.asynchbeans.WorkManager</res-type> 
      <res-auth>Container</res-auth> 
      <res-sharing-scope>Shareable</res-sharing-scope> 
   </resource-ref> 
Der Stapel wird nun durch die Arbeitsschnittstelle implementiert:
import com.ibm.websphere.asynchbeans.Work; 

public class MessageSender implements Work { 

  public MessageSender(int messages) {numberOfMessages = messages;} 

  public void run() { 
    // get connection factory/ queue 
    InitialContext ic = new InitialContext(); 
    ConnectionFactory cf = (ConnectionFactory) 
               ic.lookup("java:comp/env/jms/WMQCF"); 
    Destination destination = (Destination) ic.lookup("jms/WMQQueue"); 

    setupResources(); 
  
    // loop sending messages 
    while (!sendComplete) { 
      try { 
        // create the next message to send 
        msg.setText("message sent at "+new Date()); 
        // and send it 
        producer.send(msg); 
        // are we finished? 
        if (sendCount == numberOfMessages) {sendComplete = true); 
      } 
      catch (JMSException je) { 
          // drive reconnection 
          setupResources(); 
      } 
  } 

  public boolean isRunning() {return !sendComplete;} 

  public void release() {sendComplete = true;} 

Wenn die Stapelverarbeitung zum Beispiel aufgrund großer Nachrichten, eines langsamen Netzes oder extensiven Datenbankzugriffs (insbesondere in Verbindung mit langsamem Failover) lange dauert, beginnt der Server mit der Ausgabe von Warnungen zu blockierten Threads wie der Folgenden:

WSVR0605W: Thread "WorkManager.DefaultWorkManager : 0" (00000035) war 694061 Millisekunden aktiv und möglicherweise blockiert. There is/are 1 thread(s) in total in the server that may be hung.

Diese Warnungen lassen sich durch Verringerung der Stapelgröße oder durch Erhöhung des Zeitlimits für blockierte Threads reduzieren. Besser wäre aber die Implementierung dieser Verarbeitung in einem Enterprise JavaBean (EJB) (zum Senden von Stapeln) oder in einem Message-driven Bean (MDB) (zum Verarbeiten oder zum Verarbeiten und Antworten).

Beachten Sie, dass eine durch die Anwendung verwaltete Verbindungswiederherstellungslösung keine generelle Lösung für die Verarbeitung von Laufzeitfehlern ist und die Anwendung nach wie vor einen Mechanismus zur Behandlung von Fehlern mit Ursachen jenseits einer funktionierenden Verbindung bereitstellen muss.

Hier seien zum Beispiel der Versuch einer Anwendung genannt, eine Nachricht in eine volle Warteschlange einzureihen (2053 MQRC_Q_FULL), oder der Versuch, eine Verbindung mit einem Warteschlangenmanager mit ungültigen Berechtigungsnachweisen herzustellen (2035 MQRC_NOT_AUTHORIZED).

Außerdem muss die Anwendung 2059 MQRC_Q_MGR_NOT_AVAILABLE-Fehler handhaben können, wenn bei aktiviertem Failover keine Instanzen sofort zur Verfügung stehen. Hierzu sollte die Anwendung die JMS-Ausnahmen sofort melden, statt eigenständig und im Hintergrund zu versuchen, die Verbindung wiederherzustellen.