2019-12-09 06:39:33.189 ERROR 107132 --- [http-nio-8082-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.jms.IllegalStateException: The MessageProducer was closed due to an unrecoverable error.; nested exception is javax.jms.IllegalStateException: The MessageProducer was closed due to an unrecoverable error.] with root cause
javax.jms.JMSException: Idle link tracker, link qpid-jms:sender:ID:7300953e-f587-4ae3-b9fe-85b84e032554:1:101:1:order-update has been idle for 1800000ms TrackingId:801ab247-3f36-4470-8665-08846eb1c181_G24, SystemTracker:client-link34404815, Timestamp:2019-12-06T21:04:35 [condition = amqp:link:detach-forced]
at org.apache.qpid.jms.provider.amqp.AmqpSupport.convertToException(AmqpSupport.java:164)
at org.apache.qpid.jms.provider.amqp.AmqpSupport.convertToException(AmqpSupport.java:117)
at org.apache.qpid.jms.provider.amqp.AmqpAbstractResource.processRemoteClose(AmqpAbstractResource.java:262)
at org.apache.qpid.jms.provider.amqp.AmqpProvider.processUpdates(AmqpProvider.java:906)
at org.apache.qpid.jms.provider.amqp.AmqpProvider.access$1800(AmqpProvider.java:102)
at org.apache.qpid.jms.provider.amqp.AmqpProvider$17.run(AmqpProvider.java:792)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
compile group: 'com.microsoft.azure', name: 'azure-servicebus-spring-boot-starter', version: '0.2.0'
compile group: 'javax.jms', name: 'javax.jms-api', version: '2.0.1'
compile group: 'org.apache.qpid', name: 'qpid-jms-client', version: '0.28.0'
compile group: 'org.apache.camel', name: 'camel-jms', version: '2.24.1'
compile group: 'org.springframework.integration', name: 'spring-integration-jms', version: '5.0.4.RELEASE'
<bean id="jmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg value="${azure.jms.url}" />
<property name="username" value="${azure.jms.username}" />
<property name="password" value="${azure.jms.password}" />
<property name="clientID" value="AltaPay" />
<property name="receiveLocalOnly" value="true" />
<property name="localMessageExpiry" value="true" />
<property name="populateJMSXUserID" value="true" />
</bean>
</property>
<property name="exceptionListener">
<bean class="com.lauraashley.microservice.altapay.callback.exception.CustomJMSExceptionListener" />
</property>
<property name="sessionCacheSize" value="10" />
<property name="cacheConsumers" value="false" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="cacheLevelName" value="CACHE_NONE" />
</bean>
public class CustomJMSExceptionListener implements ExceptionListener {
private static final Logger logger = getLogger(CustomJMSExceptionListener.class);
@Override
public void onException(JMSException exception) {
// TODO Auto-generated method stub
logger.error("--------------- Catched exception with CustomJMSExceptionListener ---------------");
logger.error("Error code:"+exception.getErrorCode());
logger.error("Msg:"+exception.getMessage());
exception.printStackTrace();
logger.error("---------------------------------------------------------------------------------");
}
}
首先:未使用CustomJMSExceptionListener,配置是否正确?
该应用程序是OCC(甲骨文云商务)平台上的eccomerce应用程序,它使用java spring-boot服务进行支付集成和流程。 当订单超过了空闲时间,然后与Azure Service Bus的连接失败,并且为了重新连接,我必须重新启动Java应用程序时,会发生此错误,这是一个很大的问题,因为无法处理其他订单。我读到CachingConnectionFactory具有默认情况下为true的reconnectOnException。
我真的不明白为什么会发生这种情况以及解决该问题的解决方案。
答案 0 :(得分:1)
如上所述,这是 Azure 服务总线的预期行为,此问题在 azure-spring-boot 中未解决。目前的解决方法是将 False
值设置为 CachingConnectionFactory connectionFactory = (CachingConnectionFactory) jmsTemplate.getConnectionFactory();
connectionFactory.setCacheProducers(false);
,以便为每个会话创建新的 Producer。
@Bean
public ConnectionFactory jmsConnectionFactory(AzureServiceBusJMSProperties busJMSProperties){
final String connectionString = busJMSProperties.getConnectionString();
final String clientId = busJMSProperties.getTopicClientId();
final int idleTimeout = busJMSProperties.getIdleTimeout();
final ServiceBusKey serviceBusKey = ConnectionStringResolver.getServiceBusKey(connectionString);
final String remoteUri = String.format("amqps://%s?amqp.idleTimeout=%d&amqp.traceFrames=true",
serviceBusKey.getHost(), idleTimeout);
final JmsConnectionFactory jmsConnectionFactory =
new JmsConnectionFactory(
serviceBusKey.getSharedAccessKeyName(),
serviceBusKey.getSharedAccessKey(),
remoteUri
);
jmsConnectionFactory.setClientID(clientId);
CachingConnectionFactory cachingConnectionFactory =
new CachingConnectionFactory(jmsConnectionFactory);
// set cache producers to FALSE here
cachingConnectionFactory.setCacheProducers(false);
return cachingConnectionFactory;
}
另一种可能的方法,
public class Student {
private Address address; // keep same name address as in bean
public void setAddress(Address address) {
this.address= address;
}
}
答案 1 :(得分:0)
该异常表明Azure已关闭生产者,因为它闲置了很长时间,这意味着它没有在超时内发送消息(某些文档here)。使用CachingConnectionFactory时,您可以通过将cache producers option配置为false来解决此问题,以便按需创建生产者,但是我对此不确定,因为我没有任何方法可以对其进行测试。
这不是Qpid JMS客户端级别的错误,而是Azure的行为,在我认为链接十分钟内没有任何活动之后,它将强制关闭链接。在非基于Spring的应用程序中,您必须通过在发送时捕获JMSException来解决这个问题,要么尝试创建新的生产方并再次发送,要么通过断开整个连接并重新开始。您的反应在某种程度上取决于您对使用Azure的了解以及是否知道会发生这种情况。