项目中MDB处理异常后,调mdc.setRollbackOnly()方法后,发现JMS又发了6条消息过来。查了些资料,特此记下来。
由于mdc在项目中是注入的,整个JMS是CMT(Container Managed Transaction), mdc.setRollbackOnly()方法表示要回滚事务,但实际上的操作是通知producer重发一下。
在JBOSS的配置文件中有
这里配置了重发时间和DLQ的配置。具体参数定义猛击 这里。
DLQ全称是Dead Letter Queue,JBoss的官方网站是这样定义的:A dead letter queue stores requests that could not be processed due to some failure in the system, application or configuration.就是说,如果自己发的message被rollback了,会被重发,重发次数达到上限(MaxTimesRedelivered定义),queue中消息就会发到DLQ中。(详见http://krinsiman.blogbus.com/logs/8166898.html)
后来发现,更改上面的配置无法达到预计效果,因为Jboss使用JCA来handle JMS,DLQ是JCA的实现,而JCA默认配置里面配的参数与这里不同。 这里可以找到所有参数。
由于是在找不到如何自定义JCA的重发时间,而用 reconnectInterval属性来设置也不生效,最后找到了如下方法:
在这里设置RedeliveryDelay就有效了。
再次更新!
本来项目需要是等消息rollback后等若干时间后重新尝试,结果事实是jboss默认jms重新发6次,然后就扔到DLQ不管了。
终于找到真正修改可以起作用的地方了,以上仅供参考做研究,尝试结果是失败……
在jmx console里面,找到
再次更新,最终研究结果显示,jboss4.2.2的queue有漏洞。当mdb rollback一个message的时候,jboss会检查是否要redelivery。如果不需要或者超过redeliverylimit,就会扔到Dlq。Dlq有一个恢复次数的参数,参见上面redelivery页面。该参数仅当这个queue被刷新,即jboss重启或者该包被重新load时,才会启动。换言之,这个message在runtime的时候就被丢掉了!囧。
由于mdc在项目中是注入的,整个JMS是CMT(Container Managed Transaction), mdc.setRollbackOnly()方法表示要回滚事务,但实际上的操作是通知producer重发一下。
在JBOSS的配置文件中有
<MDBConfig> <ReconnectIntervalSec>10</ReconnectIntervalSec> <DLQConfig> <DestinationQueue>queue/DLQ</DestinationQueue> <MaxTimesRedelivered>10</MaxTimesRedelivered> <TimeToLive>0</TimeToLive> </DLQConfig> </MDBConfig> |
这里配置了重发时间和DLQ的配置。具体参数定义猛击 这里。
DLQ全称是Dead Letter Queue,JBoss的官方网站是这样定义的:A dead letter queue stores requests that could not be processed due to some failure in the system, application or configuration.就是说,如果自己发的message被rollback了,会被重发,重发次数达到上限(MaxTimesRedelivered定义),queue中消息就会发到DLQ中。(详见http://krinsiman.blogbus.com/logs/8166898.html)
后来发现,更改上面的配置无法达到预计效果,因为Jboss使用JCA来handle JMS,DLQ是JCA的实现,而JCA默认配置里面配的参数与这里不同。 这里可以找到所有参数。
由于是在找不到如何自定义JCA的重发时间,而用 reconnectInterval属性来设置也不生效,最后找到了如下方法:
In JBoss 4.x the JMS configuration (in <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=MyQueue"> <attribute name="JNDIName">queue/MyQueue</attribute> <attribute name="RedeliveryDelay">10000</attribute> <attribute name="RedeliveryLimit">3</attribute> <depends optional-attribute-name="DestinationManager"> jboss.mq:service=DestinationManager </depends> </mbean> |
In JBoss 5.x we should do this (in <mbean code="org.jboss.jms.server.destination.QueueService" name="jboss.messaging.destination:service=Queue,name=MyQueue" xmbean-dd="xmdesc/Queue-xmbean.xml"> <depends optional-attribute-name="ServerPeer"> jboss.messaging:service=ServerPeer </depends> <depends>jboss.messaging:service=PostOffice</depends> <attribute name="JNDIName">queue/MyQueue</attribute> <attribute name="RedeliveryDelay">10000</attribute> <attribute name="MaxDeliveryAttempts">3</attribute> </mbean> |
在这里设置RedeliveryDelay就有效了。
再次更新!
本来项目需要是等消息rollback后等若干时间后重新尝试,结果事实是jboss默认jms重新发6次,然后就扔到DLQ不管了。
终于找到真正修改可以起作用的地方了,以上仅供参考做研究,尝试结果是失败……
在jmx console里面,找到
jboss.mq.destination
在下面找到自己的queue,点开,有RedeliveryDelay和RedeliveryLimit。RedeliveryDelay默认为0,这是为什么rollback后,jms不停的重发。这里可以给其设一个较大的值。RedeliveryLimit默认值是-1,但实际上正如之上看到,默认是5.这里需要把它改成>=0的值,否则提交修改时会报错。再次更新,最终研究结果显示,jboss4.2.2的queue有漏洞。当mdb rollback一个message的时候,jboss会检查是否要redelivery。如果不需要或者超过redeliverylimit,就会扔到Dlq。Dlq有一个恢复次数的参数,参见上面redelivery页面。该参数仅当这个queue被刷新,即jboss重启或者该包被重新load时,才会启动。换言之,这个message在runtime的时候就被丢掉了!囧。