49
49
import org .springframework .context .ApplicationEventPublisher ;
50
50
import org .springframework .context .ApplicationEventPublisherAware ;
51
51
import org .springframework .jmx .export .annotation .ManagedOperation ;
52
+ import org .springframework .retry .RetryCallback ;
53
+ import org .springframework .retry .RetryContext ;
54
+ import org .springframework .retry .backoff .ExponentialBackOffPolicy ;
55
+ import org .springframework .retry .policy .SimpleRetryPolicy ;
56
+ import org .springframework .retry .support .RetryTemplate ;
52
57
import org .springframework .util .Assert ;
53
58
54
59
import com .rabbitmq .client .AMQP .Queue .DeclareOk ;
@@ -97,13 +102,17 @@ public class RabbitAdmin implements AmqpAdmin, ApplicationContextAware, Applicat
97
102
98
103
private final RabbitTemplate rabbitTemplate ;
99
104
105
+ private RetryTemplate retryTemplate ;
106
+
107
+ private boolean retryDisabled ;
108
+
100
109
private volatile boolean running = false ;
101
110
102
- private volatile boolean autoStartup = true ;
111
+ private boolean autoStartup = true ;
103
112
104
- private volatile ApplicationContext applicationContext ;
113
+ private ApplicationContext applicationContext ;
105
114
106
- private volatile boolean ignoreDeclarationExceptions ;
115
+ private boolean ignoreDeclarationExceptions ;
107
116
108
117
private final Object lifecycleMonitor = new Object ();
109
118
@@ -169,6 +178,7 @@ public RabbitTemplate getRabbitTemplate() {
169
178
public void declareExchange (final Exchange exchange ) {
170
179
try {
171
180
this .rabbitTemplate .execute (new ChannelCallback <Object >() {
181
+
172
182
@ Override
173
183
public Object doInRabbit (Channel channel ) throws Exception {
174
184
declareExchanges (channel , exchange );
@@ -185,6 +195,7 @@ public Object doInRabbit(Channel channel) throws Exception {
185
195
@ ManagedOperation
186
196
public boolean deleteExchange (final String exchangeName ) {
187
197
return this .rabbitTemplate .execute (new ChannelCallback <Boolean >() {
198
+
188
199
@ Override
189
200
public Boolean doInRabbit (Channel channel ) throws Exception {
190
201
if (isDeletingDefaultExchange (exchangeName )) {
@@ -219,6 +230,7 @@ public Boolean doInRabbit(Channel channel) throws Exception {
219
230
public String declareQueue (final Queue queue ) {
220
231
try {
221
232
return this .rabbitTemplate .execute (new ChannelCallback <String >() {
233
+
222
234
@ Override
223
235
public String doInRabbit (Channel channel ) throws Exception {
224
236
DeclareOk [] declared = declareQueues (channel , queue );
@@ -244,6 +256,7 @@ public String doInRabbit(Channel channel) throws Exception {
244
256
public Queue declareQueue () {
245
257
try {
246
258
DeclareOk declareOk = this .rabbitTemplate .execute (new ChannelCallback <DeclareOk >() {
259
+
247
260
@ Override
248
261
public DeclareOk doInRabbit (Channel channel ) throws Exception {
249
262
return channel .queueDeclare ();
@@ -262,6 +275,7 @@ public DeclareOk doInRabbit(Channel channel) throws Exception {
262
275
@ ManagedOperation
263
276
public boolean deleteQueue (final String queueName ) {
264
277
return this .rabbitTemplate .execute (new ChannelCallback <Boolean >() {
278
+
265
279
@ Override
266
280
public Boolean doInRabbit (Channel channel ) throws Exception {
267
281
try {
@@ -279,6 +293,7 @@ public Boolean doInRabbit(Channel channel) throws Exception {
279
293
@ ManagedOperation
280
294
public void deleteQueue (final String queueName , final boolean unused , final boolean empty ) {
281
295
this .rabbitTemplate .execute (new ChannelCallback <Object >() {
296
+
282
297
@ Override
283
298
public Object doInRabbit (Channel channel ) throws Exception {
284
299
channel .queueDelete (queueName , unused , empty );
@@ -291,6 +306,7 @@ public Object doInRabbit(Channel channel) throws Exception {
291
306
@ ManagedOperation
292
307
public void purgeQueue (final String queueName , final boolean noWait ) {
293
308
this .rabbitTemplate .execute (new ChannelCallback <Object >() {
309
+
294
310
@ Override
295
311
public Object doInRabbit (Channel channel ) throws Exception {
296
312
channel .queuePurge (queueName );
@@ -305,6 +321,7 @@ public Object doInRabbit(Channel channel) throws Exception {
305
321
public void declareBinding (final Binding binding ) {
306
322
try {
307
323
this .rabbitTemplate .execute (new ChannelCallback <Object >() {
324
+
308
325
@ Override
309
326
public Object doInRabbit (Channel channel ) throws Exception {
310
327
declareBindings (channel , binding );
@@ -321,6 +338,7 @@ public Object doInRabbit(Channel channel) throws Exception {
321
338
@ ManagedOperation
322
339
public void removeBinding (final Binding binding ) {
323
340
this .rabbitTemplate .execute (new ChannelCallback <Object >() {
341
+
324
342
@ Override
325
343
public Object doInRabbit (Channel channel ) throws Exception {
326
344
if (binding .isDestinationQueue ()) {
@@ -348,6 +366,7 @@ public Object doInRabbit(Channel channel) throws Exception {
348
366
public Properties getQueueProperties (final String queueName ) {
349
367
Assert .hasText (queueName , "'queueName' cannot be null or empty" );
350
368
return this .rabbitTemplate .execute (new ChannelCallback <Properties >() {
369
+
351
370
@ Override
352
371
public Properties doInRabbit (Channel channel ) throws Exception {
353
372
try {
@@ -382,6 +401,25 @@ public Properties doInRabbit(Channel channel) throws Exception {
382
401
});
383
402
}
384
403
404
+ /**
405
+ * Set a retry template for auto declarations. There is a race condition with
406
+ * auto-delete, exclusive queues in that the queue might still exist for a short time,
407
+ * preventing the redeclaration. The default retry configuration will try 5 times with
408
+ * an exponential backOff starting at 1 second a multiplier of 2.0 and a max interval
409
+ * of 5 seconds. To disable retry, set the argument to {@code null}. Note that this
410
+ * retry is at the macro level - all declarations will be retried within the scope of
411
+ * this template. If you supplied a {@link RabbitTemplate} that is configured with a
412
+ * {@link RetryTemplate}, its template will retry each individual declaration.
413
+ * @param retryTemplate the retry template.
414
+ * @since 1.7.8
415
+ */
416
+ public void setRetryTemplate (RetryTemplate retryTemplate ) {
417
+ this .retryTemplate = retryTemplate ;
418
+ if (retryTemplate == null ) {
419
+ this .retryDisabled = true ;
420
+ }
421
+ }
422
+
385
423
// Lifecycle implementation
386
424
387
425
public boolean isAutoStartup () {
@@ -406,6 +444,15 @@ public void afterPropertiesSet() {
406
444
return ;
407
445
}
408
446
447
+ if (this .retryTemplate == null && !this .retryDisabled ) {
448
+ this .retryTemplate = new RetryTemplate ();
449
+ this .retryTemplate .setRetryPolicy (new SimpleRetryPolicy (5 ));
450
+ ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy ();
451
+ backOffPolicy .setInitialInterval (1000 );
452
+ backOffPolicy .setMultiplier (2.0 );
453
+ backOffPolicy .setMaxInterval (5000 );
454
+ this .retryTemplate .setBackOffPolicy (backOffPolicy );
455
+ }
409
456
if (this .connectionFactory instanceof CachingConnectionFactory &&
410
457
((CachingConnectionFactory ) this .connectionFactory ).getCacheMode () == CacheMode .CONNECTION ) {
411
458
this .logger .warn ("RabbitAdmin auto declaration is not supported with CacheMode.CONNECTION" );
@@ -430,7 +477,20 @@ public void onCreate(Connection connection) {
430
477
* chatter). In fact it might even be a good thing: exclusive queues only make sense if they are
431
478
* declared for every connection. If anyone has a problem with it: use auto-startup="false".
432
479
*/
433
- initialize ();
480
+ if (RabbitAdmin .this .retryTemplate != null ) {
481
+ RabbitAdmin .this .retryTemplate .execute (
482
+ new RetryCallback <Object , RuntimeException >() {
483
+
484
+ @ Override
485
+ public Object doWithRetry (RetryContext c ) throws RuntimeException {
486
+ initialize ();
487
+ return null ;
488
+ }
489
+ });
490
+ }
491
+ else {
492
+ initialize ();
493
+ }
434
494
}
435
495
finally {
436
496
initializing .compareAndSet (true , false );
@@ -469,8 +529,8 @@ public void initialize() {
469
529
470
530
@ SuppressWarnings ("rawtypes" )
471
531
Collection <Collection > collections = this .declareCollections
472
- ? this .applicationContext .getBeansOfType (Collection .class , false , false ).values ()
473
- : Collections .<Collection >emptyList ();
532
+ ? this .applicationContext .getBeansOfType (Collection .class , false , false ).values ()
533
+ : Collections .<Collection >emptyList ();
474
534
for (Collection <?> collection : collections ) {
475
535
if (collection .size () > 0 && collection .iterator ().next () instanceof Declarable ) {
476
536
for (Object declarable : collection ) {
@@ -492,7 +552,7 @@ else if (declarable instanceof Binding) {
492
552
final Collection <Binding > bindings = filterDeclarables (contextBindings );
493
553
494
554
for (Exchange exchange : exchanges ) {
495
- if ((!exchange .isDurable () || exchange .isAutoDelete ()) && this .logger .isInfoEnabled ()) {
555
+ if ((!exchange .isDurable () || exchange .isAutoDelete ()) && this .logger .isInfoEnabled ()) {
496
556
this .logger .info ("Auto-declaring a non-durable or auto-delete Exchange ("
497
557
+ exchange .getName ()
498
558
+ ") durable:" + exchange .isDurable () + ", auto-delete:" + exchange .isAutoDelete () + ". "
@@ -517,6 +577,7 @@ else if (declarable instanceof Binding) {
517
577
return ;
518
578
}
519
579
this .rabbitTemplate .execute (new ChannelCallback <Object >() {
580
+
520
581
@ Override
521
582
public Object doInRabbit (Channel channel ) throws Exception {
522
583
declareExchanges (channel , exchanges .toArray (new Exchange [exchanges .size ()]));
@@ -540,7 +601,7 @@ private <T extends Declarable> Collection<T> filterDeclarables(Collection<T> dec
540
601
for (T declarable : declarables ) {
541
602
Collection <?> adminsWithWhichToDeclare = declarable .getDeclaringAdmins ();
542
603
if (declarable .shouldDeclare () &&
543
- (adminsWithWhichToDeclare .isEmpty () || adminsWithWhichToDeclare .contains (this ))) {
604
+ (adminsWithWhichToDeclare .isEmpty () || adminsWithWhichToDeclare .contains (this ))) {
544
605
filtered .add (declarable );
545
606
}
546
607
}
0 commit comments