我的环境是Glassfish 3.1.2 b23,在嵌入式模式下捆绑的OpenMQ(以及FWIW我也尝试过具有相同结果的LOCAL模式)在带有JDK 1.7.0_45的Windows Server 2008上。
我有一个包含非常简单的JMS组件的应用程序。 JMS组件由无状态会话bean组成,该bean生成发送到队列并由MDB使用的消息。使用Glassfish管理UI创建对象管理JMS连接池和队列。
问题是,在创建和使用消息一段时间后,通常会出现以下错误:
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:548)
at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:265)
at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:244)
at
[SNIP]
Caused by: javax.resource.spi.ResourceAllocationException: 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.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:307)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:236)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:160)
at com.sun.messaging.jms.ra.DirectConnectionFactory._allocateConnection(DirectConnectionFactory.java:543)
... 99 more
Caused by: com.sun.appserv.connectors.internal.api.PoolingException: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
at com.sun.enterprise.resource.pool.ConnectionPool.getResource(ConnectionPool.java:418)
at com.sun.enterprise.resource.pool.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:245)
at com.sun.enterprise.resource.pool.PoolManagerImpl.getResource(PoolManagerImpl.java:170)
at com.sun.enterprise.connectors.ConnectionManagerImpl.getResource(ConnectionManagerImpl.java:332)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:301)
... 103 more
当无状态EJB的@Asynchronous
方法启动的自动化进程通过项列表进行翻录并且每个项调用最终触及此消息生成的代码路径时,似乎会发生这种情况。当从一个稍微不同的代码路径调用消息生成时,一次只生成一条消息,我们没有看到这个问题。
消息只需几毫秒。生产和ms。消费。连接的最长等待时间为1分钟。最大的可以同时生成消息的线程数少于(大约2倍)与JMS连接工厂相关联的最大连接数。
生产者的会话是非jms-transactional和AUTO-ACK可以多快地连续调用?我会假设,只要producer.send(..)返回,jms连接将被返回并可供下一个生产者使用,或者在下次调用.send之前释放连接之前有一些非常轻微的延迟时间()?
使用者是一个MDB,我假设它也使用来自生产者正在使用的同一个池的JMS连接(因为那是唯一的JMS连接池)。下面的imqcmd输出表明有1个活动的消费者,但是因为合并了MDB,这意味着消费者端也可以使用X#(MDB实例的数量)连接,或者MDB只使用一个连接而不管#of合并MDB实例?
我也很好奇MDB中的异常处理。该模式取自JavaEE6样本和捕获/日志Throwable。在Throwable泄漏JMS连接时是否缺少对mdc.setRollback的调用?
在调试此问题时,我一直在使用 imqcmd 命令。具体做法是:
imqcmd 查询dst -t q -n MyQueue -u admin
---------------------------------------
Destination Name Destination Type
---------------------------------------
MyQueue Queue
On the broker specified by:
-------------------------
Host Primary Port
-------------------------
localhost 7676
Destination Name MyQueue
Destination Type Queue
Destination State RUNNING
Created Administratively false
Current Number of Messages
Actual 0
Remote 0
Held in Transaction 0
Current Message Bytes
Actual 0
Remote 0
Held in Transaction 8928
Current Number of Producers 0
Current Number of Active Consumers 1
Current Number of Backup Consumers 0
Max Number of Messages 100000
Max Total Message Bytes 10737418240
Max Bytes per Message 10485760
Max Number of Producers 100
Max Number of Active Consumers unlimited (-1)
Max Number of Backup Consumers 0
Limit Behavior REJECT_NEWEST
Consumer Flow Limit 1000
Is Local Destination false
Local Delivery is Preferred false
Use Dead Message Queue true
XML schema validation enabled false
XML schema URI List -
Reload XML schema on failure false
Successfully queried the destination.
制片人:ADetailBean.java
@Stateless
public class ADetailBean.java {
private transient static final Logger log = Logger.getLogger(ADetailBean.java);
@Resource(mappedName = "jms/MyConnectionFactory")
private ConnectionFactory jmsConnectionFactory;
@Resource(mappedName = "jms/myApp/MyQueue")
private javax.jms.Queue myQueue;
@PersistenceContext(unitName = "MyPC")
private EntityManager entityManager;
@EJB
AnotherBean anotherBean;
public void createAMessage(@NotNull AFile file, AnAction action) {
ACollection aCol = aCollectionBean.findReqColForTaskColId(file.getCollectionId());
if (aCol != null) {
ADetail aDetail = new ADetail(file.getFileNumber(), file.getCollectionId(), file.getMd5(), reqCol.getCollectionId(), action);
entityManager.persist(aDetail);
Connection jmsConnection = null;
try {
jmsConnection = jmsConnectionFactory.createConnection();
Session session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(myQueue);
AMessage aMessage = new AMessage(file.getName());
ObjectMessage myMessage = session.createObjectMessage(aMessage);
producer.send(myMessage);
} catch (JMSException e) {
log.error("Error sending message for file number: " +
file.getFileNumber() + ", md5: " + file.getMd5() +
", action: " + action + " : " + e.getMessage(), e);
} finally {
if (jmsConnection != null) {
try {
jmsConnection.close();
} catch (Exception ex) {
log.warn("Unable to close JMS connection: " + ex.getMessage());
}
}
}
}
//Other methods in this EJB
}
MDB:MyMessageListener.java
@MessageDriven(mappedName = "jms/myApp/MyQueue", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode",
propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "subscriptionDurability",
propertyValue = "Durable"),
@ActivationConfigProperty(propertyName = "clientId",
propertyValue = "myClient"),
@ActivationConfigProperty(propertyName = "subscriptionName",
propertyValue = "mySub")
})
public class MyMessageListener implements MessageListener {
private static final Logger log = Logger.getLogger(MyMessageListener.class);
@Resource
private MessageDrivenContext mdc;
@PersistenceContext(unitName = "MyPC")
private EntityManager entityManager;
@EJB
ADetailManager aDetailManager;
@EJB
ADetailBean aDetailBean;
@EJB
AFileBean aFileBean;
@Override
public void onMessage(Message message) {
log.debug("MESSAGE received from the MyQueue queue");
try {
if (message instanceof ObjectMessage) {
if (((ObjectMessage) message).getObject() != null &&
((ObjectMessage) message).getObject() instanceof ACalcMessage) {
ACalcMessage msg = (ACalcMessage) ((ObjectMessage) message).getObject();
log.debug("MESSAGE BEAN: Received aCalc msg for name: " + msg.getName());
//Wait for opportunity to process dupe recalculation for name
try {
while (!aDetailManager.obtainNameLock(msg.getName())) {
log.debug("Waiting to obtain name lock for name: " + msg.getName());
Thread.sleep(1000);
}
aDetail aDetail = aDetailBean.findNext(msg.getName());
//Do some processing including JPA queries and entity merges
entityManager.remove(aDetail);
}
} finally {
aDetailManager.releaseNameLock(msg.getName());
}
}
}
} catch (JMSException e) {
log.error("Error processing message: " + e.getMessage());
mdc.setRollbackOnly();
} catch (Throwable te) {
log.error("Error processing message: ", te);
}
}
}
MyConnectionFactory管理对象设置
Pool Name: jms/MyConnectionFactory
JNDI Name: jms/MyConnectionFactory
Resource Type: javax.jms.ConnectionFactory
Status: [X] Enabled
Initial Minimum Pool Size: 8
Maximum Pool Size: 64
Pool Resize Quantity: 2
Idle Timeout: 300 seconds
Max Wait Time: 60000 Milliseconds
Transaction Support: EMPTY (I assume this means the default level, which is XA?)
Connection Validation: [X] Required
No Additional Properties
在连接池高级标签中:
Validate At Most Once: 0 Seconds
Leak Timeout: 0 Seconds
Leak Reclaim: [ ]
Creation Retry Attempts: 0
Retry Interval: 10 Seconds
Pooling: [X] Enabled
Lazy Association: [ ] Enabled
Lazy Connection Enlistment: [ ] Enabled
Associate with Thread: [ ] Enabled
Match Connections: [X] Enabled
Max Connection Usage: 0
队列管理对象设置如下所示:
JNDI Name: jms/myApp/MyQueue
Resource Adapter: jmsra
Resource Type: javax.jms.Queue
Class Name: com.sun.messaging.Queue
Status: [X] Enabled
Additional Properties:
Name | Value
---- -------
Name MyQueue