在发生以下情形时,消息会给重发给客户端:
客户端可以通过ActiveMQConnection.getRedeliveryPolicy()
或 ActiveMQConnectionFactory.getRedeliveryPolicyMap()
来覆盖策略设置。
方法:
RedeliveryPolicy policy = connection.getRedeliveryPolicy();
policy.setInitialRedeliveryDelay(500);
policy.setBackOffMultiplier(2);
policy.setUseExponentialBackOff(true);
policy.setMaximumRedeliveries(2);
当一个消息被redelivered超过maximumRedeliveries(缺省为6次,具体设置请参考后面的链接)次数时,会给broker发送一个"Poison ack",这个消息被认为是a poison pill,这时broker会将这个消息发送到DLQ,以便后续处理。
缺省的死信队列是ActiveMQ.DLQ,所有不能投递的消息都会被发送到这个队列,这将会导致难以管理。你可以在activemq.xml这个配置文件的destinationPolicy
配置individualDeadLetterStrategy
,它可以让给为一个给定的queue或topic指定特定的死信队列前缀。如果你希望所有的queue都拥有自己的死信队列,你可以使用通配符。
示例:
<broker>
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">">
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true"/>
deadLetterStrategy>
policyEntry>
policyEntries>
policyMap>
destinationPolicy>
broker>
如果你只想丢弃过期的消息,不想发送到死信队列,你可以在一个死信队列策略中配置processExpired=false
。
<broker>
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">">
<deadLetterStrategy>
<sharedDeadLetterStrategy processExpired="false" />
deadLetterStrategy>
policyEntry>
policyEntries>
policyMap>
destinationPolicy>
broker>
默认情况下,ActiveMQ不会将不能投递的非持久消息放到死信队列。如果你希望将非持久消息存储到死信队列,你可以在死信队列的策略中设置processNonPersistent="true"
。
<broker>
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue=">">
<deadLetterStrategy>
<sharedDeadLetterStrategy processNonPersistent="true" />
deadLetterStrategy>
policyEntry>
policyEntries>
policyMap>
destinationPolicy>
broker>
默认情况下,ActiveMQ永远不会使发送到DLQ的消息失效。 但是,在ActiveMQ 5.12中,deadLetterStrategy支持到期属性,其值以毫秒为单位。
<broker>
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry queue="QueueWhereItIsOkToExpireDLQEntries">
<deadLetterStrategy>
<.... expiration="300000"/>
deadLetterStrategy>
policyEntry>
policyEntries>
policyMap>
destinationPolicy>
broker>
从ActiveMQ5.9开始,一个Destination的policyEntry
支持丢弃的deadLetterStrategy。
<deadLetterStrategy>
<discarding/>
deadLetterStrategy>
这个与丢弃插件的功能相同,但这个是基于每个Destination的。丢弃插件支持正则表达式匹配,这在某些情况下很有用。
此插件允许全部或基于Java SE的正则表达式匹配的queue和topic,丢弃发送到DLQ中的消息。这在使用ConstantPendingMessageLimit策略或其他逐出规则,但不想有一个其他的消费者来清理DLQ时很有用。
下面是一个丢弃所有内容的一个基本配置:
<beans>
<broker>
<plugins>
<discardingDLQBrokerPlugin dropAll="true" dropTemporaryTopics="true" dropTemporaryQueues="true"/>
plugins>
broker>
beans>
下面是一个稍微复杂点的例子:
<beans>
<broker>
<plugins>
<discardingDLQBrokerPlugin dropOnly="MY.EXAMPLE.TOPIC.29 MY.EXAMPLE.QUEUE.87" reportInterval="1000"/>
plugins>
broker>
beans>
这个例子中,只针对指定的queue和topic有效。各个destination用空格隔开。
reportInterval属性用于表示我们输出丢弃的消息的频率 - 使用0来禁用。
下面是一个使用正则表达式的例子:
<beans>
<broker>
<plugins>
<discardingDLQBrokerPlugin dropOnly="MY.EXAMPLE.TOPIC.[0-9]{3} MY.EXAMPLE.QUEUE.[0-9]{3}" reportInterval="3000"/>
plugins>
broker>
beans>
这里匹配的是以000~999结尾的目的地。
默认情况下,在消息重新投递次数达到配置的最大投递次数(或默认的6次),broker会将消息放入DLQ。我们可以使用broker消息重发插件来改变这一行为。即在一定延迟后,将消息重新投递给原始Destination,如果达到最大重试次数,则放入DLQ。
<broker schedulerSupport="true">
<plugins>
<redeliveryPlugin fallbackToDeadLetter="true"
sendToDlqIfMaxRetriesExceeded="true">
<redeliveryPolicyMap>
<redeliveryPolicyMap>
<redeliveryPolicyEntries>
<redeliveryPolicy queue="SpecialQueue"
maximumRedeliveries="4"
redeliveryDelay="10000"/>
redeliveryPolicyEntries>
<defaultEntry>
<redeliveryPolicy maximumRedeliveries="4"
initialRedeliveryDelay="5000"
redeliveryDelay="10000"/>
defaultEntry>
redeliveryPolicyMap>
redeliveryPolicyMap>
redeliveryPlugin>
plugins>
broker>
sendToDlqIfMaxRetriesExceeded:如果为true,则在达到最大重试次数后,会发送到DLQ,否则会删除该消息。
参考:http://activemq.apache.org/message-redelivery-and-dlq-handling.html