Given:
- A JMS message queue.
- A timer service which puts messages to that queue periodically (from a database).
- A JEE6 message-driven bean which reads from the queue.
- The timer service and the message-driven bean are part of different deployment units.
Problem:
The message-driven bean cannot be undeployed, without breaking the workflow state, as long as messages are work in process. Because of that, we stop the timer service first and wait until all messages are finished.
Is there a way to automate that behavior? Or is it possible to prevent undeployment if the timer service is still running? We are currently using JBoss 4.2.3.
Non-Solutions:
- Refactoring the deployment units, because it would involve several departments.
- I know that a system crash won't be covered and that a bulletproof solution should include a recovery strategy.
Each deployed MDB has a JMX management interface MBean. The ObjectName of this MBean varies according to deployment (and might also be different between versions of JBoss). I am using JBoss 4.3 and the ObjectName format is:
Domain Name: jboss.j2ee
service: EJB3
name: <MDB Name>
ear: <EAR Name> (if applicable)
jar: <JAR Name>
If your timer service is a JBoss ServiceMBean, you can make your MDB depend on the timer by using the JBoss @Depends("the timer service ObjectName") annotation. This will force the timer service to start before the MDB starts (so preferably, make the timer service have some post start delay) but more importantly, I believe the reverse will occur on undeploy and the timer service should stop first, then the MDB.
If that works, it takes care of ordering, but I don't think you can force the MDB not undeploy while the timer is running. The details of your application might not support this, but one way you might consider resolving this issue is to use the JBoss Quartz JCA Inflow Adapter which will essentially bind the timer and message processor into one (it's like an MDB, but it receives timer events rather than messages), ridding you of having to wrestle with dependencies between two components.
================================ Attempt #2 ================================
Ok, so you want to prevent the MDB from stopping while the feeding queue has a depth of more than zero. This approach should work for you, although it is highly specific to JBoss.
- Implement a JMX NotificationListener that listens on state changes of the MDB Delegate MBean.
- You can also implement a JMX NotificationFilter to narrow down the specific events you want to listen on.
- The state change you're looking for is on the attribute State and the transition you're looking for is 3 --> 1 (Started --> Stopping)
- JMX notifications in [this version of] JBoss are issued synchronously and will block until the notification listener returns. When your listener receives this notification, start a polling loop on the MDB's feeding queue MBean (did not ask if you were using JBoss Messaging but I will assume you are). While the MessageCount is > 0, you keep polling. When the queue's message count is zero, the listener returns and the MDB will stop.
- Make sure to add a brief sleep in your polling loop, as well as a polling timeout (in case things get whacky).
- You might also consider not returning until the message count is 0 for at least n polling loops in case there is some uncommited message in transit which might not show up in the message count.
The bottom line is that while your attribute change listener is being called, message will continue to be processed. When the attribute change listener returns, the MDB stop will continue.
If your JMS implementation is the local in-VM JBoss Messaging, the queue message count will be available in the queue's management MBean. For any other setup, you may need to make a proprietary JMS API call to get the queue's message count, or, using a more brute force approach, you can simply request a JMS QueueBrowser and count the number of messages.
来源:https://stackoverflow.com/questions/5792016/how-to-stop-message-processing-before-undeploying