Skip to content

Commit 9c8b86b

Browse files
committed
RabbitMQ - RetryTemplate customization hook
Provide a mechanism so that users can customize `RetryTemplate`s used in `RabbitTemplate` and listeners. An example would be to add a retry listener so the user can monitor/log retry attempts. https://stackoverflow.com/questions/48331502/logging-exceptions-thrown-by-message-listeners-for-spring-amqp/48332001#48332001 Or, to set a custom `RetryContextCache`. temp
1 parent cc450cc commit 9c8b86b

File tree

8 files changed

+244
-23
lines changed

8 files changed

+244
-23
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/AbstractRabbitListenerContainerFactoryConfigurer.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer;
2525
import org.springframework.amqp.support.converter.MessageConverter;
2626
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.ListenerRetry;
27+
import org.springframework.retry.support.RetryTemplate;
2728
import org.springframework.util.Assert;
2829

2930
/**
@@ -42,6 +43,8 @@ public abstract class AbstractRabbitListenerContainerFactoryConfigurer<T extends
4243

4344
private RabbitProperties rabbitProperties;
4445

46+
private RabbitListenerRetryTemplateCustomizer retryTemplateCustomizer;
47+
4548
/**
4649
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
4750
* converter should be used.
@@ -59,6 +62,14 @@ protected void setMessageRecoverer(MessageRecoverer messageRecoverer) {
5962
this.messageRecoverer = messageRecoverer;
6063
}
6164

65+
/**
66+
* Set the {@link RabbitListenerRetryTemplateCustomizer} to use.
67+
* @param retryTemplateCustomizer the customizer
68+
*/
69+
public void setRetryTemplateCustomizer(RabbitListenerRetryTemplateCustomizer retryTemplateCustomizer) {
70+
this.retryTemplateCustomizer = retryTemplateCustomizer;
71+
}
72+
6273
/**
6374
* Set the {@link RabbitProperties} to use.
6475
* @param rabbitProperties the {@link RabbitProperties}
@@ -107,9 +118,9 @@ protected void configure(T factory, ConnectionFactory connectionFactory,
107118
RetryInterceptorBuilder<?> builder = (retryConfig.isStateless()
108119
? RetryInterceptorBuilder.stateless()
109120
: RetryInterceptorBuilder.stateful());
110-
builder.maxAttempts(retryConfig.getMaxAttempts());
111-
builder.backOffOptions(retryConfig.getInitialInterval(),
112-
retryConfig.getMultiplier(), retryConfig.getMaxInterval());
121+
RetryTemplate template = RabbitAutoConfiguration.createRetryTemplate(retryConfig,
122+
this.retryTemplateCustomizer);
123+
builder.retryOperations(template);
113124
MessageRecoverer recoverer = (this.messageRecoverer != null
114125
? this.messageRecoverer : new RejectAndDontRequeueRecoverer());
115126
builder.recoverer(recoverer);

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,13 +45,17 @@ class RabbitAnnotationDrivenConfiguration {
4545

4646
private final ObjectProvider<MessageRecoverer> messageRecoverer;
4747

48+
private final ObjectProvider<RabbitListenerRetryTemplateCustomizer> retryTemplateCustomizer;
49+
4850
private final RabbitProperties properties;
4951

5052
RabbitAnnotationDrivenConfiguration(ObjectProvider<MessageConverter> messageConverter,
5153
ObjectProvider<MessageRecoverer> messageRecoverer,
54+
ObjectProvider<RabbitListenerRetryTemplateCustomizer> retryCustomizer,
5255
RabbitProperties properties) {
5356
this.messageConverter = messageConverter;
5457
this.messageRecoverer = messageRecoverer;
58+
this.retryTemplateCustomizer = retryCustomizer;
5559
this.properties = properties;
5660
}
5761

@@ -61,6 +65,7 @@ public SimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContai
6165
SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer();
6266
configurer.setMessageConverter(this.messageConverter.getIfUnique());
6367
configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique());
68+
configurer.setRetryTemplateCustomizer(this.retryTemplateCustomizer.getIfUnique());
6469
configurer.setRabbitProperties(this.properties);
6570
return configurer;
6671
}
@@ -82,6 +87,7 @@ public DirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContai
8287
DirectRabbitListenerContainerFactoryConfigurer configurer = new DirectRabbitListenerContainerFactoryConfigurer();
8388
configurer.setMessageConverter(this.messageConverter.getIfUnique());
8489
configurer.setMessageRecoverer(this.messageRecoverer.getIfUnique());
90+
configurer.setRetryTemplateCustomizer(this.retryTemplateCustomizer.getIfUnique());
8591
configurer.setRabbitProperties(this.properties);
8692
return configurer;
8793
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfiguration.java

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3535
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3636
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
37+
import org.springframework.boot.autoconfigure.retry.RetryTemplateCustomizer;
3738
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3839
import org.springframework.boot.context.properties.PropertyMapper;
3940
import org.springframework.context.annotation.Bean;
@@ -151,12 +152,16 @@ protected static class RabbitTemplateConfiguration {
151152

152153
private final ObjectProvider<MessageConverter> messageConverter;
153154

155+
private final ObjectProvider<RabbitTemplateRetryTemplateCustomizer> retryTemplateCustomizer;
156+
154157
private final RabbitProperties properties;
155158

156159
public RabbitTemplateConfiguration(
157160
ObjectProvider<MessageConverter> messageConverter,
161+
ObjectProvider<RabbitTemplateRetryTemplateCustomizer> retryTemplateCustomizer,
158162
RabbitProperties properties) {
159163
this.messageConverter = messageConverter;
164+
this.retryTemplateCustomizer = retryTemplateCustomizer;
160165
this.properties = properties;
161166
}
162167

@@ -173,7 +178,8 @@ public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
173178
template.setMandatory(determineMandatoryFlag());
174179
RabbitProperties.Template properties = this.properties.getTemplate();
175180
if (properties.getRetry().isEnabled()) {
176-
template.setRetryTemplate(createRetryTemplate(properties.getRetry()));
181+
template.setRetryTemplate(createRetryTemplate(properties.getRetry(),
182+
this.retryTemplateCustomizer.getIfUnique()));
177183
}
178184
map.from(properties::getReceiveTimeout).whenNonNull()
179185
.to(template::setReceiveTimeout);
@@ -189,21 +195,6 @@ private boolean determineMandatoryFlag() {
189195
return (mandatory != null ? mandatory : this.properties.isPublisherReturns());
190196
}
191197

192-
private RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) {
193-
PropertyMapper map = PropertyMapper.get();
194-
RetryTemplate template = new RetryTemplate();
195-
SimpleRetryPolicy policy = new SimpleRetryPolicy();
196-
map.from(properties::getMaxAttempts).to(policy::setMaxAttempts);
197-
template.setRetryPolicy(policy);
198-
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
199-
map.from(properties::getInitialInterval)
200-
.to(backOffPolicy::setInitialInterval);
201-
map.from(properties::getMultiplier).to(backOffPolicy::setMultiplier);
202-
map.from(properties::getMaxInterval).to(backOffPolicy::setMaxInterval);
203-
template.setBackOffPolicy(backOffPolicy);
204-
return template;
205-
}
206-
207198
@Bean
208199
@ConditionalOnSingleCandidate(ConnectionFactory.class)
209200
@ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
@@ -229,4 +220,23 @@ public RabbitMessagingTemplate rabbitMessagingTemplate(
229220

230221
}
231222

223+
static RetryTemplate createRetryTemplate(RabbitProperties.Retry properties,
224+
RetryTemplateCustomizer customizer) {
225+
PropertyMapper map = PropertyMapper.get();
226+
RetryTemplate template = new RetryTemplate();
227+
SimpleRetryPolicy policy = new SimpleRetryPolicy();
228+
map.from(properties::getMaxAttempts).to(policy::setMaxAttempts);
229+
template.setRetryPolicy(policy);
230+
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
231+
map.from(properties::getInitialInterval)
232+
.to(backOffPolicy::setInitialInterval);
233+
map.from(properties::getMultiplier).to(backOffPolicy::setMultiplier);
234+
map.from(properties::getMaxInterval).to(backOffPolicy::setMaxInterval);
235+
template.setBackOffPolicy(backOffPolicy);
236+
if (customizer != null) {
237+
customizer.customize(template);
238+
}
239+
return template;
240+
}
241+
232242
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.amqp;
18+
19+
import org.springframework.boot.autoconfigure.retry.RetryTemplateCustomizer;
20+
21+
/**
22+
* A marker interface for a {@link RetryTemplateCustomizer} for RabbitMQ listeners.
23+
*
24+
* @author Gary Russell
25+
* @since 2.0
26+
*
27+
*/
28+
public interface RabbitListenerRetryTemplateCustomizer extends RetryTemplateCustomizer {
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.amqp;
18+
19+
import org.springframework.boot.autoconfigure.retry.RetryTemplateCustomizer;
20+
21+
/**
22+
* A marker interface for a {@link RetryTemplateCustomizer} for RabbitMQ templates.
23+
*
24+
* @author Gary Russell
25+
* @since 2.0
26+
*
27+
*/
28+
public interface RabbitTemplateRetryTemplateCustomizer extends RetryTemplateCustomizer {
29+
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.retry;
18+
19+
import org.springframework.retry.support.RetryTemplate;
20+
21+
/**
22+
* A customizer for a {@link RetryTemplate}, for example, to add a RetryListener.
23+
*
24+
* @author Gary Russell
25+
* @since 2.0
26+
*
27+
*/
28+
public interface RetryTemplateCustomizer {
29+
30+
/**
31+
* Customize the template.
32+
* @param template the template.
33+
* @param properties the properties.
34+
*/
35+
void customize(RetryTemplate template);
36+
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration for Spring Retry.
19+
*/
20+
package org.springframework.boot.autoconfigure.retry;

0 commit comments

Comments
 (0)