users@glassfish.java.net

Findings for “Cannot allocate more connections” exception.

From: <glassfish_at_javadesktop.org>
Date: Sun, 13 Sep 2009 15:28:54 PDT

Dear forum reader
I’m currently involved in a project where the project team is developing against a GlassFish server using Netbeans 6.7.1. The project is basically that we basically read a lot of records from a database using a scheduled task and put the records on a JMS queue. Those messages are later consumed and processed in various ways.

One problem that we had, and which I seen quite a few postings about, is that sometimes we get a large quantity of new records which causes GlassFish to throw an exception that we ran out of connections in the connection pool, i.e:

[i]com.sun.messaging.jms.JMSException: MQRA:DCF:allocation failure:createConnection:Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
        at com.sun.messaging.jms.ra.DirectConnectionFactory._allocateConnection(DirectConnectionFactory.java:574)
        at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:262) [/i]

Most answers to this seems to indicate that the reason for this problem is that the code doesn’t close the connection properly after use but I’m not sure that it’s the whole answer. To investigate the problem I created a simple Enterprise Application test project in Netbeans. The project consists of a Servlet (to initiate the JMS sending), a stateless Session bean and a Message Driven Bean (MDB) to consume the messages.

The Servlet only do a single call to the Session-EJB’s method feed() which contains a for-loop to send a number of strings to the queue. The MDB consumes the messages and logs the text to the GlassFish log. The actual JMS send code is auto generated by Netbeans “Insert code” function thus I guess it can be considered to be error free.

I.e. this is a very simple test application but still, as soon as the number of JMS messages sent to the queue is equal to the max-pool-size in the Glassfish configuration the sending fails and the exception is thrown, so for some reason the connections are not returned to the connection pool even if the close() methods are called correctly.

To investigate the problem further one thing I tried was to move the loop that generated messages from inside the Session bean to the calling Servlet, i.e. I put the for-loop in the Servlet code and called a business method on the Session bean called feedOne() that sends a single JMS message to the queue and viola, the exception is no more. Still, the only thing I did was to move the for-loop that called feedOne() from within the Session bean’s (the feed()) method to the processRequest() method of the Servlet. I.e. it seems like there is something happening when crossing the EJB “boundary” that lets the connection return to the connection pool.

The code for the Session bean is pasted below together with the code for the Servlet.

Since it seems to work if the I call the message generating session bean from outside the bean I also experimented by calling the session bean from another session bean, both with local and remote interfaces, but in those cases the problem persisted, i.e. an exception was thrown as soon as the number of sent messages equaled the max-connections in the Glassfish configuration.

I would be very happy for comments on this since it causes big problems in the current project. As I see it I can’t find a way to properly send a batch of JMS messages from within an EJB without the risk of this dreadful exception. Of course we could do a fix involving a Servlet but that would complicate the design so if it’s at all possible we would like to avoid it.

Regards, Ola

Session bean code:
@Stateless
public class FeedQueueBean implements FeedQueueLocal {
        @Resource(name = "jms/testQueue")
        private Queue testQueue;
        @Resource(name = "jms/testQueueFactory")
        private ConnectionFactory testQueueFactory;

        public void feed() {
                Logger.getLogger(FeedQueueBean.class.getName()).log(Level.INFO, "sendJMSMessageToTestQueue() feeding.....");

                for (int i = 0; i < 40; i++) {
                        feedOne(new Integer(i));
                }
        }

        public void feedOne(Integer value) {
                Logger.getLogger(FeedQueueBean.class.getName()).log(Level.INFO, String.format("sendJMSMessageToTestQueue() feedOne %s", value.toString()));
                try {
                        Logger.getLogger(FeedQueueBean.class.getName()).log(Level.INFO, String.format("sendJMSMessageToTestQueue() feed %d, %s.", value.intValue(), new Date().toString()));
                        sendJMSMessageToTestQueue(value);
                } catch (JMSException ex) {
                        Logger.getLogger(FeedQueueBean.class.getName()).log(Level.SEVERE, "sendJMSMessageToTestQueue() failed.", ex);
                }
        }

        private Message createJMSMessageForjmsTestQueue(Session session, Object messageData) throws JMSException {
                // TODO create and populate message to send
                TextMessage tm = session.createTextMessage();
                tm.setText(messageData.toString());
                return tm;
        }

        private void sendJMSMessageToTestQueue(Object messageData) throws JMSException {
                Connection connection = null;
                Session session = null;
                try {
                        connection = testQueueFactory.createConnection();
                        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                        MessageProducer messageProducer = session.createProducer(testQueue);
                        messageProducer.send(createJMSMessageForjmsTestQueue(session, messageData));
                } finally {
                        if (session != null) {
                                try {
                                        session.close();
                                } catch (JMSException e) {
                                        Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
                                }
                        }
                        if (connection != null) {
                                connection.close();
                        }
                }
        }

Servlet code:

//Causes exception:
feedQueueBean.feed();

//Works:
// for (int i = 0; i < 50; i++) {
// feedQueueBean.feedOne(new Integer(i));
//}
[Message sent by forum member 'glassola' (ola.theander_at_myola.se)]

http://forums.java.net/jive/thread.jspa?messageID=363838