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.
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
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();
}
}
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
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.