2929import java .util .Map ;
3030import java .util .Queue ;
3131import java .util .Set ;
32+ import java .util .concurrent .CompletableFuture ;
3233import java .util .concurrent .ConcurrentHashMap ;
3334import java .util .concurrent .ConcurrentLinkedQueue ;
3435import java .util .concurrent .ConcurrentSkipListSet ;
@@ -915,7 +916,17 @@ void setNotifier(Runnable notifier) {
915916 void stop () {
916917 this .state = ConsumerState .STOP ;
917918 if (KinesisMessageDrivenChannelAdapter .this .lockRegistry != null ) {
918- KinesisMessageDrivenChannelAdapter .this .shardConsumerManager .unlock (this .key );
919+ LockCompletableFuture unlockFuture = new LockCompletableFuture (this .key );
920+ KinesisMessageDrivenChannelAdapter .this .shardConsumerManager .unlock (unlockFuture );
921+ try {
922+ unlockFuture .get (1 , TimeUnit .SECONDS );
923+ }
924+ catch (Exception ex ) {
925+ if (ex instanceof InterruptedException ) {
926+ Thread .currentThread ().interrupt ();
927+ }
928+ logger .info ("The lock for key '" + this .key + "' was not unlocked in time" , ex );
929+ }
919930 }
920931 if (this .notifier != null ) {
921932 this .notifier .run ();
@@ -929,6 +940,10 @@ void close() {
929940
930941 void execute () {
931942 if (this .task == null ) {
943+ if (!renewLockIfAny ()) {
944+ return ;
945+ }
946+
932947 switch (this .state ) {
933948 case NEW :
934949 case EXPIRED :
@@ -1007,6 +1022,36 @@ void execute() {
10071022 }
10081023 }
10091024
1025+ private boolean renewLockIfAny () {
1026+ if (KinesisMessageDrivenChannelAdapter .this .lockRegistry != null && this .state == ConsumerState .CONSUME ) {
1027+ LockCompletableFuture renewLockFuture = new LockCompletableFuture (this .key );
1028+ KinesisMessageDrivenChannelAdapter .this .shardConsumerManager .renewLock (renewLockFuture );
1029+ boolean lockRenewed = false ;
1030+ try {
1031+ lockRenewed = renewLockFuture .get (1 , TimeUnit .SECONDS );
1032+ }
1033+ catch (Exception ex ) {
1034+ if (ex instanceof InterruptedException ) {
1035+ Thread .currentThread ().interrupt ();
1036+ }
1037+ logger .info ("The lock for key '" + this .key + "' was not renewed in time" , ex );
1038+ }
1039+
1040+ if (!lockRenewed && this .state == ConsumerState .CONSUME ) {
1041+ this .state = ConsumerState .STOP ;
1042+ this .checkpointer .close ();
1043+ if (this .notifier != null ) {
1044+ this .notifier .run ();
1045+ }
1046+ if (KinesisMessageDrivenChannelAdapter .this .active ) {
1047+ KinesisMessageDrivenChannelAdapter .this .shardConsumerManager .addShardToConsume (this .shardOffset );
1048+ }
1049+ return false ;
1050+ }
1051+ }
1052+ return true ;
1053+ }
1054+
10101055 private Runnable processTask () {
10111056 return () -> {
10121057 GetRecordsRequest getRecordsRequest = new GetRecordsRequest ();
@@ -1368,7 +1413,9 @@ private final class ShardConsumerManager implements SchedulingAwareRunnable {
13681413
13691414 private final Map <String , Lock > locks = new HashMap <>();
13701415
1371- private final Queue <String > forUnlocking = new ConcurrentLinkedQueue <>();
1416+ private final Queue <LockCompletableFuture > forUnlocking = new ConcurrentLinkedQueue <>();
1417+
1418+ private final Queue <LockCompletableFuture > forRenewing = new ConcurrentLinkedQueue <>();
13721419
13731420 ShardConsumerManager () {
13741421 }
@@ -1379,15 +1426,18 @@ void addShardToConsume(KinesisShardOffset kinesisShardOffset) {
13791426 this .shardOffsetsToConsumer .put (lockKey , kinesisShardOffset );
13801427 }
13811428
1382- void unlock (String lockKey ) {
1383- this .forUnlocking .add (lockKey );
1429+ void unlock (LockCompletableFuture unlockFuture ) {
1430+ this .forUnlocking .add (unlockFuture );
1431+ }
1432+
1433+ void renewLock (LockCompletableFuture renewLockFuture ) {
1434+ this .forRenewing .add (renewLockFuture );
13841435 }
13851436
13861437 @ Override
13871438 public void run () {
13881439 try {
13891440 while (!Thread .currentThread ().isInterrupted ()) {
1390-
13911441 this .shardOffsetsToConsumer
13921442 .entrySet ()
13931443 .removeIf (
@@ -1418,9 +1468,9 @@ public void run() {
14181468 });
14191469
14201470 while (KinesisMessageDrivenChannelAdapter .this .lockRegistry != null ) {
1421- String lockKey = this .forUnlocking .poll ();
1422- if (lockKey != null ) {
1423- Lock lock = this .locks .remove (lockKey );
1471+ LockCompletableFuture forUnlocking = this .forUnlocking .poll ();
1472+ if (forUnlocking != null ) {
1473+ Lock lock = this .locks .remove (forUnlocking . lockKey );
14241474 if (lock != null ) {
14251475 try {
14261476 lock .unlock ();
@@ -1429,13 +1479,48 @@ public void run() {
14291479 logger .error ("Error during unlocking: " + lock , e );
14301480 }
14311481 }
1482+ forUnlocking .complete (true );
14321483 }
14331484 else {
14341485 break ;
14351486 }
14361487 }
14371488
1438- sleep (250 , new IllegalStateException ("ShardConsumerManager Thread [" + this + "] has been interrupted" ), true );
1489+ while (KinesisMessageDrivenChannelAdapter .this .lockRegistry != null ) {
1490+ LockCompletableFuture lockFuture = this .forRenewing .poll ();
1491+ if (lockFuture != null ) {
1492+ Lock lock = this .locks .get (lockFuture .lockKey );
1493+ if (lock != null ) {
1494+ try {
1495+ if (lock .tryLock ()) {
1496+ try {
1497+ lockFuture .complete (true );
1498+ }
1499+ finally {
1500+ lock .unlock ();
1501+ }
1502+ }
1503+ else {
1504+ lockFuture .complete (false );
1505+ this .locks .remove (lockFuture .lockKey );
1506+ }
1507+ }
1508+ catch (Exception e ) {
1509+ logger .error ("Error during locking: " + lock , e );
1510+ }
1511+ }
1512+ else {
1513+ lockFuture .complete (false );
1514+ }
1515+ }
1516+ else {
1517+ break ;
1518+ }
1519+ }
1520+
1521+ sleep (250 ,
1522+ new IllegalStateException ("ShardConsumerManager Thread [" + this + "] has been interrupted" ),
1523+ true );
14391524 }
14401525 }
14411526 finally {
@@ -1461,4 +1546,14 @@ public boolean isLongLived() {
14611546
14621547 }
14631548
1549+ private final static class LockCompletableFuture extends CompletableFuture <Boolean > {
1550+
1551+ private final String lockKey ;
1552+
1553+ LockCompletableFuture (String lockKey ) {
1554+ this .lockKey = lockKey ;
1555+ }
1556+
1557+ }
1558+
14641559}
0 commit comments