@@ -90,6 +90,8 @@ public class AutorecoveringConnection implements RecoverableConnection, NetworkC
90
90
// be created after application code has initiated shutdown.
91
91
private final Object recoveryLock = new Object ();
92
92
93
+ private final RetryHandler retryHandler ;
94
+
93
95
public AutorecoveringConnection (ConnectionParams params , FrameHandlerFactory f , List <Address > addrs ) {
94
96
this (params , f , new ListAddressResolver (addrs ));
95
97
}
@@ -109,6 +111,8 @@ public AutorecoveringConnection(ConnectionParams params, FrameHandlerFactory f,
109
111
110
112
this .topologyRecoveryFilter = params .getTopologyRecoveryFilter () == null ?
111
113
letAllPassFilter () : params .getTopologyRecoveryFilter ();
114
+
115
+ this .retryHandler = params .getTopologyRecoveryRetryHandler ();
112
116
}
113
117
114
118
private void setupErrorOnWriteListenerForPotentialRecovery () {
@@ -633,6 +637,10 @@ private void recoverChannels(final RecoveryAwareAMQConnection newConn) {
633
637
}
634
638
}
635
639
640
+ void recoverChannel (AutorecoveringChannel channel ) throws IOException {
641
+ channel .automaticallyRecover (this , this .delegate );
642
+ }
643
+
636
644
private void notifyRecoveryListenersComplete () {
637
645
for (RecoveryListener f : Utility .copy (this .recoveryListeners )) {
638
646
f .handleRecovery (this );
@@ -654,16 +662,16 @@ private void recoverTopology(final ExecutorService executor) {
654
662
if (executor == null ) {
655
663
// recover entities in serial on the main connection thread
656
664
for (final RecordedExchange exchange : Utility .copy (recordedExchanges ).values ()) {
657
- recoverExchange (exchange );
665
+ recoverExchange (exchange , true );
658
666
}
659
667
for (final Map .Entry <String , RecordedQueue > entry : Utility .copy (recordedQueues ).entrySet ()) {
660
- recoverQueue (entry .getKey (), entry .getValue ());
668
+ recoverQueue (entry .getKey (), entry .getValue (), true );
661
669
}
662
670
for (final RecordedBinding b : Utility .copy (recordedBindings )) {
663
- recoverBinding (b );
671
+ recoverBinding (b , true );
664
672
}
665
673
for (final Map .Entry <String , RecordedConsumer > entry : Utility .copy (consumers ).entrySet ()) {
666
- recoverConsumer (entry .getKey (), entry .getValue ());
674
+ recoverConsumer (entry .getKey (), entry .getValue (), true );
667
675
}
668
676
} else {
669
677
// Support recovering entities in parallel for connections that have a lot of queues, bindings, & consumers
@@ -683,11 +691,22 @@ private void recoverTopology(final ExecutorService executor) {
683
691
}
684
692
}
685
693
686
- private void recoverExchange (final RecordedExchange x ) {
694
+ private void recoverExchange (RecordedExchange x , boolean retry ) {
687
695
// recorded exchanges are guaranteed to be non-predefined (we filter out predefined ones in exchangeDeclare). MK.
688
696
try {
689
697
if (topologyRecoveryFilter .filterExchange (x )) {
690
- x .recover ();
698
+ if (retry ) {
699
+ final RecordedExchange entity = x ;
700
+ x = (RecordedExchange ) wrapRetryIfNecessary (x , new Callable <Void >() {
701
+ @ Override
702
+ public Void call () throws Exception {
703
+ entity .recover ();
704
+ return null ;
705
+ }
706
+ }).getRecordedEntity ();
707
+ } else {
708
+ x .recover ();
709
+ }
691
710
LOGGER .debug ("{} has recovered" , x );
692
711
}
693
712
} catch (Exception cause ) {
@@ -698,12 +717,23 @@ private void recoverExchange(final RecordedExchange x) {
698
717
}
699
718
}
700
719
701
- private void recoverQueue (final String oldName , final RecordedQueue q ) {
702
720
721
+ void recoverQueue (final String oldName , RecordedQueue q , boolean retry ) {
703
722
try {
704
723
if (topologyRecoveryFilter .filterQueue (q )) {
705
724
LOGGER .debug ("Recovering {}" , q );
706
- q .recover ();
725
+ if (retry ) {
726
+ final RecordedQueue entity = q ;
727
+ q = (RecordedQueue ) wrapRetryIfNecessary (q , new Callable <Void >() {
728
+ @ Override
729
+ public Void call () throws Exception {
730
+ entity .recover ();
731
+ return null ;
732
+ }
733
+ }).getRecordedEntity ();
734
+ } else {
735
+ q .recover ();
736
+ }
707
737
String newName = q .getName ();
708
738
if (!oldName .equals (newName )) {
709
739
// make sure server-named queues are re-added with
@@ -734,10 +764,21 @@ private void recoverQueue(final String oldName, final RecordedQueue q) {
734
764
}
735
765
}
736
766
737
- private void recoverBinding (final RecordedBinding b ) {
767
+ private void recoverBinding (RecordedBinding b , boolean retry ) {
738
768
try {
739
769
if (this .topologyRecoveryFilter .filterBinding (b )) {
740
- b .recover ();
770
+ if (retry ) {
771
+ final RecordedBinding entity = b ;
772
+ b = (RecordedBinding ) wrapRetryIfNecessary (b , new Callable <Void >() {
773
+ @ Override
774
+ public Void call () throws Exception {
775
+ entity .recover ();
776
+ return null ;
777
+ }
778
+ }).getRecordedEntity ();
779
+ } else {
780
+ b .recover ();
781
+ }
741
782
LOGGER .debug ("{} has recovered" , b );
742
783
}
743
784
} catch (Exception cause ) {
@@ -748,11 +789,25 @@ private void recoverBinding(final RecordedBinding b) {
748
789
}
749
790
}
750
791
751
- private void recoverConsumer (final String tag , final RecordedConsumer consumer ) {
792
+ private void recoverConsumer (final String tag , RecordedConsumer consumer , boolean retry ) {
752
793
try {
753
794
if (this .topologyRecoveryFilter .filterConsumer (consumer )) {
754
795
LOGGER .debug ("Recovering {}" , consumer );
755
- String newTag = consumer .recover ();
796
+ String newTag = null ;
797
+ if (retry ) {
798
+ final RecordedConsumer entity = consumer ;
799
+ RetryResult retryResult = wrapRetryIfNecessary (consumer , new Callable <String >() {
800
+ @ Override
801
+ public String call () throws Exception {
802
+ return entity .recover ();
803
+ }
804
+ });
805
+ consumer = (RecordedConsumer ) retryResult .getRecordedEntity ();
806
+ newTag = (String ) retryResult .getResult ();
807
+ } else {
808
+ newTag = consumer .recover ();
809
+ }
810
+
756
811
// make sure server-generated tags are re-added. MK.
757
812
if (tag != null && !tag .equals (newTag )) {
758
813
synchronized (this .consumers ) {
@@ -775,6 +830,33 @@ private void recoverConsumer(final String tag, final RecordedConsumer consumer)
775
830
}
776
831
}
777
832
833
+ private <T > RetryResult wrapRetryIfNecessary (RecordedEntity entity , Callable <T > recoveryAction ) throws Exception {
834
+ if (this .retryHandler == null ) {
835
+ T result = recoveryAction .call ();
836
+ return new RetryResult (entity , result );
837
+ } else {
838
+ try {
839
+ T result = recoveryAction .call ();
840
+ return new RetryResult (entity , result );
841
+ } catch (Exception e ) {
842
+ RetryContext retryContext = new RetryContext (entity , e , this );
843
+ RetryResult retryResult ;
844
+ if (entity instanceof RecordedQueue ) {
845
+ retryResult = this .retryHandler .retryQueueRecovery (retryContext );
846
+ } else if (entity instanceof RecordedExchange ) {
847
+ retryResult = this .retryHandler .retryExchangeRecovery (retryContext );
848
+ } else if (entity instanceof RecordedBinding ) {
849
+ retryResult = this .retryHandler .retryBindingRecovery (retryContext );
850
+ } else if (entity instanceof RecordedConsumer ) {
851
+ retryResult = this .retryHandler .retryConsumerRecovery (retryContext );
852
+ } else {
853
+ throw new IllegalArgumentException ("Unknown type of recorded entity: " + entity );
854
+ }
855
+ return retryResult ;
856
+ }
857
+ }
858
+ }
859
+
778
860
private void propagateQueueNameChangeToBindings (String oldName , String newName ) {
779
861
for (RecordedBinding b : Utility .copy (this .recordedBindings )) {
780
862
if (b .getDestination ().equals (oldName )) {
@@ -825,15 +907,15 @@ private <E extends RecordedEntity> List<Callable<Object>> groupEntitiesByChannel
825
907
public void run () {
826
908
for (final E entity : entityList ) {
827
909
if (entity instanceof RecordedExchange ) {
828
- recoverExchange ((RecordedExchange )entity );
910
+ recoverExchange ((RecordedExchange )entity , true );
829
911
} else if (entity instanceof RecordedQueue ) {
830
912
final RecordedQueue q = (RecordedQueue ) entity ;
831
- recoverQueue (q .getName (), q );
913
+ recoverQueue (q .getName (), q , true );
832
914
} else if (entity instanceof RecordedBinding ) {
833
- recoverBinding ((RecordedBinding ) entity );
915
+ recoverBinding ((RecordedBinding ) entity , true );
834
916
} else if (entity instanceof RecordedConsumer ) {
835
917
final RecordedConsumer c = (RecordedConsumer ) entity ;
836
- recoverConsumer (c .getConsumerTag (), c );
918
+ recoverConsumer (c .getConsumerTag (), c , true );
837
919
}
838
920
}
839
921
}
0 commit comments