48
48
import org .springframework .kafka .core .KafkaTemplate ;
49
49
import org .springframework .kafka .core .ProducerFactory ;
50
50
import org .springframework .kafka .listener .ContainerProperties ;
51
+ import org .springframework .kafka .listener .DefaultErrorHandler ;
51
52
import org .springframework .kafka .support .KafkaHeaders ;
52
53
import org .springframework .kafka .test .EmbeddedKafkaBroker ;
53
54
import org .springframework .kafka .test .context .EmbeddedKafka ;
56
57
import org .springframework .stereotype .Component ;
57
58
import org .springframework .test .annotation .DirtiesContext ;
58
59
import org .springframework .test .context .junit .jupiter .SpringJUnitConfig ;
60
+ import org .springframework .util .backoff .FixedBackOff ;
59
61
60
62
/**
61
63
* @author Tomaz Fernandes
64
+ * @author Cenk Akin
62
65
* @since 2.8.3
63
66
*/
64
67
@ SpringJUnitConfig
65
68
@ DirtiesContext
66
69
@ EmbeddedKafka (topics = { RetryTopicSameContainerFactoryIntegrationTests .FIRST_TOPIC ,
67
- RetryTopicSameContainerFactoryIntegrationTests .SECOND_TOPIC }, partitions = 1 )
70
+ RetryTopicSameContainerFactoryIntegrationTests .SECOND_TOPIC , RetryTopicSameContainerFactoryIntegrationTests . THIRD_TOPIC }, partitions = 1 )
68
71
public class RetryTopicSameContainerFactoryIntegrationTests {
69
72
70
73
private static final Logger logger = LoggerFactory .getLogger (RetryTopicSameContainerFactoryIntegrationTests .class );
@@ -73,6 +76,8 @@ public class RetryTopicSameContainerFactoryIntegrationTests {
73
76
74
77
public final static String SECOND_TOPIC = "myRetryTopic2" ;
75
78
79
+ public final static String THIRD_TOPIC = "myRetryTopic3" ;
80
+
76
81
@ Autowired
77
82
private KafkaTemplate <String , String > sendKafkaTemplate ;
78
83
@@ -85,10 +90,13 @@ void shouldRetryFirstAndSecondTopics(@Autowired RetryTopicComponentFactory compo
85
90
sendKafkaTemplate .send (FIRST_TOPIC , "Testing topic 1" );
86
91
logger .debug ("Sending message to topic " + SECOND_TOPIC );
87
92
sendKafkaTemplate .send (SECOND_TOPIC , "Testing topic 2" );
88
- assertThat (awaitLatch (latchContainer .countDownLatch1 )).isTrue ();
89
- assertThat (awaitLatch (latchContainer .countDownLatch2 )).isTrue ();
90
- assertThat (awaitLatch (latchContainer .countDownLatchDlt1 )).isTrue ();
91
- assertThat (awaitLatch (latchContainer .countDownLatchDlt2 )).isTrue ();
93
+ logger .debug ("Sending message to topic " + THIRD_TOPIC );
94
+ sendKafkaTemplate .send (THIRD_TOPIC , "Testing topic 3" );
95
+ assertThat (awaitLatch (latchContainer .countDownLatchFirstRetryable )).isTrue ();
96
+ assertThat (awaitLatch (latchContainer .countDownLatchDltOne )).isTrue ();
97
+ assertThat (awaitLatch (latchContainer .countDownLatchSecondRetryable )).isTrue ();
98
+ assertThat (awaitLatch (latchContainer .countDownLatchDltSecond )).isTrue ();
99
+ assertThat (awaitLatch (latchContainer .countDownLatchBasic )).isTrue ();
92
100
assertThat (awaitLatch (latchContainer .customizerLatch )).isTrue ();
93
101
verify (componentFactory ).destinationTopicResolver ();
94
102
}
@@ -116,14 +124,14 @@ static class FirstRetryableKafkaListener {
116
124
topicSuffixingStrategy = TopicSuffixingStrategy .SUFFIX_WITH_INDEX_VALUE )
117
125
@ KafkaListener (topics = RetryTopicSameContainerFactoryIntegrationTests .FIRST_TOPIC )
118
126
public void listen (String in , @ Header (KafkaHeaders .RECEIVED_TOPIC ) String topic ) {
119
- countDownLatchContainer .countDownLatch1 .countDown ();
127
+ countDownLatchContainer .countDownLatchFirstRetryable .countDown ();
120
128
logger .warn (in + " from " + topic );
121
- throw new RuntimeException ("from RetryableKafkaListener " );
129
+ throw new RuntimeException ("from FirstRetryableKafkaListener " );
122
130
}
123
131
124
132
@ DltHandler
125
133
public void dlt (String in , @ Header (KafkaHeaders .RECEIVED_TOPIC ) String topic ) {
126
- countDownLatchContainer .countDownLatchDlt1 .countDown ();
134
+ countDownLatchContainer .countDownLatchDltOne .countDown ();
127
135
logger .warn (in + " from " + topic );
128
136
}
129
137
}
@@ -137,28 +145,39 @@ static class SecondRetryableKafkaListener {
137
145
@ RetryableTopic
138
146
@ KafkaListener (topics = RetryTopicSameContainerFactoryIntegrationTests .SECOND_TOPIC )
139
147
public void listen (String in , @ Header (KafkaHeaders .RECEIVED_TOPIC ) String topic ) {
140
- countDownLatchContainer .countDownLatch2 .countDown ();
141
- logger .warn (in + " from " + topic );
148
+ countDownLatchContainer .countDownLatchSecondRetryable .countDown ();
149
+ logger .info (in + " from " + topic );
142
150
throw new RuntimeException ("from SecondRetryableKafkaListener" );
143
151
}
144
152
145
-
146
153
@ DltHandler
147
154
public void dlt (String in , @ Header (KafkaHeaders .RECEIVED_TOPIC ) String topic ) {
148
- countDownLatchContainer .countDownLatchDlt2 .countDown ();
155
+ countDownLatchContainer .countDownLatchDltSecond .countDown ();
149
156
logger .warn (in + " from " + topic );
150
157
}
151
158
}
152
159
160
+
161
+ @ Component
162
+ static class BasicKafkaListener {
163
+
164
+ @ KafkaListener (topics = RetryTopicSameContainerFactoryIntegrationTests .THIRD_TOPIC )
165
+ public void listen (String in , @ Header (KafkaHeaders .RECEIVED_TOPIC ) String topic ) {
166
+ logger .info (in + " from " + topic );
167
+ throw new RuntimeException ("from BasicKafkaListener" );
168
+ }
169
+ }
170
+
153
171
@ Component
154
172
static class CountDownLatchContainer {
155
173
156
- CountDownLatch countDownLatch1 = new CountDownLatch (4 );
157
- CountDownLatch countDownLatch2 = new CountDownLatch (3 );
174
+ CountDownLatch countDownLatchFirstRetryable = new CountDownLatch (4 );
175
+ CountDownLatch countDownLatchSecondRetryable = new CountDownLatch (3 );
176
+ CountDownLatch countDownLatchDltOne = new CountDownLatch (1 );
177
+ CountDownLatch countDownLatchDltSecond = new CountDownLatch (1 );
158
178
159
- CountDownLatch countDownLatchDlt1 = new CountDownLatch (1 );
160
- CountDownLatch countDownLatchDlt2 = new CountDownLatch (1 );
161
- CountDownLatch customizerLatch = new CountDownLatch (9 );
179
+ CountDownLatch countDownLatchBasic = new CountDownLatch (1 );
180
+ CountDownLatch customizerLatch = new CountDownLatch (10 );
162
181
}
163
182
164
183
@ EnableKafka
@@ -183,6 +202,11 @@ SecondRetryableKafkaListener secondRetryableKafkaListener() {
183
202
return new SecondRetryableKafkaListener ();
184
203
}
185
204
205
+ @ Bean
206
+ BasicKafkaListener basicKafkaListener () {
207
+ return new BasicKafkaListener ();
208
+ }
209
+
186
210
@ Bean
187
211
public ConcurrentKafkaListenerContainerFactory <String , String > kafkaListenerContainerFactory (
188
212
ConsumerFactory <String , String > consumerFactory , CountDownLatchContainer latchContainer ) {
@@ -194,6 +218,10 @@ public ConcurrentKafkaListenerContainerFactory<String, String> kafkaListenerCont
194
218
props .setPollTimeout (50L );
195
219
props .setIdlePartitionEventInterval (100L );
196
220
factory .setConsumerFactory (consumerFactory );
221
+ DefaultErrorHandler errorHandler = new DefaultErrorHandler (
222
+ (cr , ex ) -> latchContainer .countDownLatchBasic .countDown (),
223
+ new FixedBackOff (0 , 2 ));
224
+ factory .setCommonErrorHandler (errorHandler );
197
225
factory .setConcurrency (1 );
198
226
factory .setContainerCustomizer (
199
227
container -> latchContainer .customizerLatch .countDown ());
0 commit comments