8.4.8 Message-driven bean best practices
- Delegate business logic to another handler.
Message-driven beans should delegate the business logic concerned with processing the contents of a message to a stateless session bean. MDBs can then focus on what they were designed to do, which is processing messages.
An additional benefit of this approach is that the business logic within the stateless session bean can be reused by other EJB clients.
- Do not maintain a client-specific state within an MDB.
As discussed earlier, MDB instances should not maintain any conversational state on behalf of a client. This enables the EJB container to maintain a pool of MDB instances and to select any instance from this pool to process an incoming message. However, this does not prevent an MDB from maintaining a state that is not specific to a client, for example, datasource references or references to another EJB.
- Avoid large message bodies.
A JMS message probably will travel over the network at some point in its life. It will definitely need to be handled by the JMS provider. All of these components contribute to the overall performance and reliability of the system. The amount of data contained in the body of a JMS message should be kept as small as possible to avoid impacting the performance of the network or the JMS provider.
- Minimize message processing time.
Instances of an MDB are allocated from the method-ready pool to process incoming messages. These instances are not returned to the method-ready pool until message processing is complete. Therefore, the longer it takes for an MDB to process a message, the longer it is unavailable for reallocation.
If an application is required to process a high volume of messages, the number an MDB instances in the method-ready pool could be rapidly depleted if each message requires a significant processing. The EJB container would then need to spend valuable CPU time creating additional MDB instances for the method-ready pool, further impacting the performance of the application.
Additional care must be taken if other resources are enlisted into a global transaction during the processing of a message. The EJB container will not attempt to commit the global transaction until the MDB's onMessage method returns. Until the global transaction commits, these resources cannot be released on the resource managers in question.
For these reasons, the amount of time required to process each message should be kept to a minimum.
- Avoid dependencies on message ordering.
Try to avoid having an application making any assumptions with regard to the order in which JMS messages are processed. This is due to the fact that appservers enable the concurrent processing of JMS messages by MDBs and that some messages can take longer to process than others. Consequently, a message delivered later in a sequence of messages might finish message processing before a message delivered earlier in the sequence. It might be possible to configure the appserver in such a way that messaging ordering is maintained within the application, but this is usually done at the expense of performance or architectural flexibility, such as the inability to deploy an application to a cluster.
- Be aware of poison messages.
Sometimes, a badly-formatted JMS message arrives at a destination. Such a message might cause an exception to be thrown within the MDB during message processing. An MDB that is making use of container-managed transactions then marks the transaction for rollback. The EJB container n rolls back the transaction, causing the message to be placed back on the queue for redelivery. However, the same problem occurs within the MDB the next time the message is delivered. In this situation, such a message might be received, and then returned to the queue, repeatedly. These messages are known as poison messages.
Fortunately, some messaging providers have implemented mechanisms that can detect poison messages and redirect them to another destination. WebSphere MQ and the service integration bus are two such providers.