@@ -746,6 +746,8 @@ private final class ListenerConsumer implements SchedulingAwareRunnable, Consume
746
746
747
747
private final Set <TopicPartition > pausedForNack = new HashSet <>();
748
748
749
+ private final boolean pauseImmediate = this .containerProperties .isPauseImmediate ();
750
+
749
751
private Map <TopicPartition , OffsetMetadata > definedPartitions ;
750
752
751
753
private int count ;
@@ -782,7 +784,7 @@ private final class ListenerConsumer implements SchedulingAwareRunnable, Consume
782
784
783
785
private boolean receivedSome ;
784
786
785
- private ConsumerRecords <K , V > pendingRecordsAfterError ;
787
+ private ConsumerRecords <K , V > remainingRecords ;
786
788
787
789
private boolean pauseForPending ;
788
790
@@ -1381,7 +1383,7 @@ protected void pollAndInvoke() {
1381
1383
debugRecords (records );
1382
1384
1383
1385
invokeIfHaveRecords (records );
1384
- if (this .pendingRecordsAfterError == null ) {
1386
+ if (this .remainingRecords == null ) {
1385
1387
resumeConsumerIfNeccessary ();
1386
1388
if (!this .consumerPaused ) {
1387
1389
resumePartitionsIfNecessary ();
@@ -1395,9 +1397,9 @@ private void doProcessCommits() {
1395
1397
processCommits ();
1396
1398
}
1397
1399
catch (CommitFailedException cfe ) {
1398
- if (this .pendingRecordsAfterError != null && !this .isBatchListener ) {
1399
- ConsumerRecords <K , V > pending = this .pendingRecordsAfterError ;
1400
- this .pendingRecordsAfterError = null ;
1400
+ if (this .remainingRecords != null && !this .isBatchListener ) {
1401
+ ConsumerRecords <K , V > pending = this .remainingRecords ;
1402
+ this .remainingRecords = null ;
1401
1403
List <ConsumerRecord <?, ?>> records = new ArrayList <>();
1402
1404
Iterator <ConsumerRecord <K , V >> iterator = pending .iterator ();
1403
1405
while (iterator .hasNext ()) {
@@ -1563,19 +1565,19 @@ private ConsumerRecords<K, V> doPoll() {
1563
1565
}
1564
1566
else {
1565
1567
records = pollConsumer ();
1566
- if (this .pendingRecordsAfterError != null ) {
1568
+ if (this .remainingRecords != null ) {
1567
1569
int howManyRecords = records .count ();
1568
1570
if (howManyRecords > 0 ) {
1569
1571
this .logger .error (() -> String .format ("Poll returned %d record(s) while consumer was paused "
1570
1572
+ "after an error; emergency stop invoked to avoid message loss" , howManyRecords ));
1571
1573
KafkaMessageListenerContainer .this .emergencyStop .run ();
1572
1574
}
1573
- TopicPartition firstPart = this .pendingRecordsAfterError .partitions ().iterator ().next ();
1575
+ TopicPartition firstPart = this .remainingRecords .partitions ().iterator ().next ();
1574
1576
boolean isPaused = isPaused () || isPartitionPauseRequested (firstPart );
1575
1577
this .logger .debug (() -> "First pending after error: " + firstPart + "; paused: " + isPaused );
1576
1578
if (!isPaused ) {
1577
- records = this .pendingRecordsAfterError ;
1578
- this .pendingRecordsAfterError = null ;
1579
+ records = this .remainingRecords ;
1580
+ this .remainingRecords = null ;
1579
1581
}
1580
1582
}
1581
1583
captureOffsets (records );
@@ -2225,8 +2227,8 @@ private RuntimeException doInvokeBatchListener(final ConsumerRecords<K, V> recor
2225
2227
private void commitOffsetsIfNeeded (final ConsumerRecords <K , V > records ) {
2226
2228
if ((!this .autoCommit && this .commonErrorHandler .isAckAfterHandle ())
2227
2229
|| this .producer != null ) {
2228
- if (this .pendingRecordsAfterError != null ) {
2229
- ConsumerRecord <K , V > firstUncommitted = this .pendingRecordsAfterError .iterator ().next ();
2230
+ if (this .remainingRecords != null ) {
2231
+ ConsumerRecord <K , V > firstUncommitted = this .remainingRecords .iterator ().next ();
2230
2232
Iterator <ConsumerRecord <K , V >> it = records .iterator ();
2231
2233
while (it .hasNext ()) {
2232
2234
ConsumerRecord <K , V > next = it .next ();
@@ -2392,7 +2394,7 @@ private void invokeBatchErrorHandler(final ConsumerRecords<K, V> records,
2392
2394
records , this .consumer , KafkaMessageListenerContainer .this .thisOrParentContainer ,
2393
2395
() -> invokeBatchOnMessageWithRecordsOrList (records , list ));
2394
2396
if (!afterHandling .isEmpty ()) {
2395
- this .pendingRecordsAfterError = afterHandling ;
2397
+ this .remainingRecords = afterHandling ;
2396
2398
this .pauseForPending = true ;
2397
2399
}
2398
2400
}
@@ -2444,7 +2446,9 @@ private void invokeRecordListenerInTx(final ConsumerRecords<K, V> records) {
2444
2446
handleNack (records , record );
2445
2447
break ;
2446
2448
}
2447
-
2449
+ if (checkImmediatePause (iterator )) {
2450
+ break ;
2451
+ }
2448
2452
}
2449
2453
}
2450
2454
@@ -2523,9 +2527,28 @@ private void doInvokeWithRecords(final ConsumerRecords<K, V> records) {
2523
2527
handleNack (records , record );
2524
2528
break ;
2525
2529
}
2530
+ if (checkImmediatePause (iterator )) {
2531
+ break ;
2532
+ }
2526
2533
}
2527
2534
}
2528
2535
2536
+ private boolean checkImmediatePause (Iterator <ConsumerRecord <K , V >> iterator ) {
2537
+ if (isPaused () && this .pauseImmediate ) {
2538
+ Map <TopicPartition , List <ConsumerRecord <K , V >>> remaining = new HashMap <>();
2539
+ while (iterator .hasNext ()) {
2540
+ ConsumerRecord <K , V > next = iterator .next ();
2541
+ remaining .computeIfAbsent (new TopicPartition (next .topic (), next .partition ()),
2542
+ tp -> new ArrayList <ConsumerRecord <K , V >>()).add (next );
2543
+ }
2544
+ if (remaining .size () > 0 ) {
2545
+ this .remainingRecords = new ConsumerRecords <>(remaining );
2546
+ return true ;
2547
+ }
2548
+ }
2549
+ return false ;
2550
+ }
2551
+
2529
2552
@ Nullable
2530
2553
private ConsumerRecords <K , V > checkEarlyIntercept (ConsumerRecords <K , V > nextArg ) {
2531
2554
ConsumerRecords <K , V > next = nextArg ;
@@ -2669,8 +2692,8 @@ private void commitOffsetsIfNeeded(final ConsumerRecord<K, V> record) {
2669
2692
if (this .isManualAck ) {
2670
2693
this .commitRecovered = true ;
2671
2694
}
2672
- if (this .pendingRecordsAfterError == null
2673
- || !record .equals (this .pendingRecordsAfterError .iterator ().next ())) {
2695
+ if (this .remainingRecords == null
2696
+ || !record .equals (this .remainingRecords .iterator ().next ())) {
2674
2697
ackCurrent (record );
2675
2698
}
2676
2699
if (this .isManualAck ) {
@@ -2787,7 +2810,7 @@ private void invokeErrorHandler(final ConsumerRecord<K, V> record,
2787
2810
tp -> new ArrayList <ConsumerRecord <K , V >>()).add (next );
2788
2811
}
2789
2812
if (records .size () > 0 ) {
2790
- this .pendingRecordsAfterError = new ConsumerRecords <>(records );
2813
+ this .remainingRecords = new ConsumerRecords <>(records );
2791
2814
this .pauseForPending = true ;
2792
2815
}
2793
2816
}
0 commit comments