我正在尝试修改我的spring-amqp项目,以便在抛出某个异常类型时,始终重新排列该消息。否则,重试x次,然后拒绝。
以下是相关配置xml
<rabbit:connection-factory id="rabbitMqConnectionFactory" host="localhost" port="5672" />
<rabbit:template id="rabbitTemplate" connection-factory="rabbitMqConnectionFactory"
exchange="my.exchange" routing-key="foo"/>
<bean id="myListenerContainer" class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="rabbitMqConnectionFactory" />
<property name="messageListener" ref="myMessageListener" />
<property name="concurrentConsumers" value="2" />
<property name="queueNames" value="work.q" />
<property name="adviceChain" ref="myRetryInterceptor" />
</bean>
这是相关代码
@Bean(name="myRetryInterceptor")
public MethodInterceptor getInterceptor() {
return RetryInterceptorBuilder.stateless()
.retryPolicy(getRetryPolicy())
.recoverer(new RejectAndDontRequeueRecoverer())
.build();
}
private RetryPolicy getRetryPolicy() {
return new SimpleRetryPolicy(5, Collections.EMPTY_MAP) {
@Override
public boolean canRetry(RetryContext context) {
Throwable t = context.getLastThrowable();
if ((t!=null) && (t.getCause() instanceof com.test.MessageRetryException)) {
return true;
}
return super.canRetry(context);
}
};
}
我注意到当我故意在myMessageListener中抛出一个com.test.MessageRetryException时,同一个线程会一遍又一遍地给出该消息。这与没有修改弹簧类的实现形成对比。在这种情况下,消息交替地给予一个消费者线程然后另一个消费者线程。我做错了吗?
@Bean(name="myRetryInterceptor")
//all consumers are given the message here
public MethodInterceptor getInterceptor() {
return RetryInterceptorBuilder.stateful()
.maxAttempts(5)
.recoverer(new RejectAndDontRequeueRecoverer())
.build();
}
答案 0 :(得分:2)
没有;你做错了什么;无状态重试是在原始传递的范围内完成的(在同一个线程上)。在重试耗尽之前不会发生消息拒绝。
另一方面,有状态重试拒绝每次尝试的传递,它将被重新提交并(可能)由另一个线程处理。由于rabbitmq现在在队列的头部重新排队被拒绝的消息,因此切换到有状态恢复并没有任何好处,它需要消息ID头才能工作(因此可以确定消息的状态)。
编辑:嗯 - 我看到你正在使用有状态重试;所以我希望重新发生在备用线程上。
如果您可以在Gist或某个地方发布DEBUG日志;我可以看看。但是,正如我所说,无国籍重审更简单。