tamizhgeek commented on code in PR #255:
URL: 
https://github.com/apache/flink-connector-aws/pull/255#discussion_r3815590733


##########
flink-connector-aws/flink-connector-aws-kinesis-streams/src/main/java/org/apache/flink/connector/kinesis/source/reader/fanout/StreamConsumerRegistrar.java:
##########
@@ -143,6 +144,90 @@ public void deregisterStreamConsumer() {
         }
     }
 
+    /**
+     * Ensures an EFO consumer exists and is {@code ACTIVE}: waits out any 
in-progress {@code
+     * DELETING}, then registers if missing. A concurrent {@link 
ResourceInUseException} on register
+     * is treated as another caller winning the same race, not an error.
+     *
+     * @throws KinesisStreamsSourceException if it never reaches {@code 
ACTIVE} within {@code
+     *     maxAttempts}.
+     */
+    public static String ensureActiveConsumer(
+            StreamProxy kinesisStreamProxy,
+            String streamArn,
+            String consumerName,
+            Duration baseDelay,
+            Duration maxDelay,
+            int maxAttempts) {
+        for (int attempt = 1; ; attempt++) {
+            ConsumerStatus status;
+            String consumerArn;
+            try {
+                DescribeStreamConsumerResponse response =
+                        kinesisStreamProxy.describeStreamConsumer(streamArn, 
consumerName);
+                status = response.consumerDescription().consumerStatus();
+                consumerArn = response.consumerDescription().consumerARN();
+            } catch (ResourceNotFoundException e) {
+                status = null;
+                consumerArn = null;
+            }
+
+            if (status == ConsumerStatus.ACTIVE) {
+                return consumerArn;
+            }
+
+            if (status == null) {
+                try {
+                    LOG.info("Registering stream consumer - {}::{}", 
streamArn, consumerName);
+                    kinesisStreamProxy.registerStreamConsumer(streamArn, 
consumerName);
+                } catch (ResourceInUseException e) {
+                    LOG.info(
+                            "EFO consumer '{}' on stream {} appeared 
concurrently while "
+                                    + "registering; waiting for it to become 
ACTIVE.",
+                            consumerName,
+                            streamArn);
+                }
+            } else {
+                LOG.info(
+                        "EFO consumer '{}' on stream {} is {}; waiting before 
re-checking.",
+                        consumerName,
+                        streamArn,
+                        status);
+            }
+
+            if (attempt >= maxAttempts) {
+                throw new KinesisStreamsSourceException(
+                        "EFO consumer '"
+                                + consumerName
+                                + "' on stream "
+                                + streamArn
+                                + " did not become ACTIVE after "
+                                + maxAttempts
+                                + " attempts.",
+                        null);
+            }
+
+            sleepUninterruptibly(computeBackoffMillis(baseDelay, maxDelay, 
attempt));
+        }
+    }
+
+    /** Full-jitter exponential backoff: random duration between 0 and 
min(base*2^(n-1), max). */
+    private static long computeBackoffMillis(Duration baseDelay, Duration 
maxDelay, int attempt) {
+        long exponential = baseDelay.toMillis() * (1L << Math.min(attempt - 1, 
20));
+        long capped = Math.min(exponential, maxDelay.toMillis());
+        return ThreadLocalRandom.current().nextLong(capped + 1);
+    }
+
+    private static void sleepUninterruptibly(long millis) {

Review Comment:
   I think this should be called sleepInterruptibly?



##########
flink-connector-aws/flink-connector-aws-kinesis-streams/src/main/java/org/apache/flink/connector/kinesis/source/reader/fanout/StreamConsumerRegistrar.java:
##########
@@ -143,6 +144,90 @@ public void deregisterStreamConsumer() {
         }
     }
 
+    /**
+     * Ensures an EFO consumer exists and is {@code ACTIVE}: waits out any 
in-progress {@code
+     * DELETING}, then registers if missing. A concurrent {@link 
ResourceInUseException} on register
+     * is treated as another caller winning the same race, not an error.
+     *
+     * @throws KinesisStreamsSourceException if it never reaches {@code 
ACTIVE} within {@code
+     *     maxAttempts}.
+     */
+    public static String ensureActiveConsumer(
+            StreamProxy kinesisStreamProxy,
+            String streamArn,
+            String consumerName,
+            Duration baseDelay,
+            Duration maxDelay,
+            int maxAttempts) {
+        for (int attempt = 1; ; attempt++) {
+            ConsumerStatus status;
+            String consumerArn;
+            try {
+                DescribeStreamConsumerResponse response =
+                        kinesisStreamProxy.describeStreamConsumer(streamArn, 
consumerName);
+                status = response.consumerDescription().consumerStatus();
+                consumerArn = response.consumerDescription().consumerARN();
+            } catch (ResourceNotFoundException e) {
+                status = null;
+                consumerArn = null;
+            }
+
+            if (status == ConsumerStatus.ACTIVE) {
+                return consumerArn;
+            }
+
+            if (status == null) {
+                try {
+                    LOG.info("Registering stream consumer - {}::{}", 
streamArn, consumerName);
+                    kinesisStreamProxy.registerStreamConsumer(streamArn, 
consumerName);
+                } catch (ResourceInUseException e) {
+                    LOG.info(
+                            "EFO consumer '{}' on stream {} appeared 
concurrently while "
+                                    + "registering; waiting for it to become 
ACTIVE.",
+                            consumerName,
+                            streamArn);
+                }
+            } else {
+                LOG.info(
+                        "EFO consumer '{}' on stream {} is {}; waiting before 
re-checking.",
+                        consumerName,
+                        streamArn,
+                        status);
+            }
+
+            if (attempt >= maxAttempts) {
+                throw new KinesisStreamsSourceException(
+                        "EFO consumer '"
+                                + consumerName
+                                + "' on stream "
+                                + streamArn
+                                + " did not become ACTIVE after "
+                                + maxAttempts
+                                + " attempts.",
+                        null);
+            }
+
+            sleepUninterruptibly(computeBackoffMillis(baseDelay, maxDelay, 
attempt));
+        }
+    }
+
+    /** Full-jitter exponential backoff: random duration between 0 and 
min(base*2^(n-1), max). */

Review Comment:
   I would use 
software.amazon.awssdk.core.retry.backoff.FullJitterBackoffStrategy instead of 
building our own backoff strategy



##########
flink-connector-aws/flink-connector-aws-kinesis-streams/src/main/java/org/apache/flink/connector/kinesis/source/reader/fanout/StreamConsumerRegistrar.java:
##########
@@ -143,6 +144,90 @@ public void deregisterStreamConsumer() {
         }
     }
 
+    /**
+     * Ensures an EFO consumer exists and is {@code ACTIVE}: waits out any 
in-progress {@code
+     * DELETING}, then registers if missing. A concurrent {@link 
ResourceInUseException} on register
+     * is treated as another caller winning the same race, not an error.
+     *
+     * @throws KinesisStreamsSourceException if it never reaches {@code 
ACTIVE} within {@code
+     *     maxAttempts}.
+     */
+    public static String ensureActiveConsumer(
+            StreamProxy kinesisStreamProxy,
+            String streamArn,
+            String consumerName,
+            Duration baseDelay,
+            Duration maxDelay,
+            int maxAttempts) {
+        for (int attempt = 1; ; attempt++) {
+            ConsumerStatus status;
+            String consumerArn;
+            try {
+                DescribeStreamConsumerResponse response =
+                        kinesisStreamProxy.describeStreamConsumer(streamArn, 
consumerName);
+                status = response.consumerDescription().consumerStatus();
+                consumerArn = response.consumerDescription().consumerARN();
+            } catch (ResourceNotFoundException e) {
+                status = null;
+                consumerArn = null;
+            }
+
+            if (status == ConsumerStatus.ACTIVE) {
+                return consumerArn;
+            }
+
+            if (status == null) {
+                try {
+                    LOG.info("Registering stream consumer - {}::{}", 
streamArn, consumerName);
+                    kinesisStreamProxy.registerStreamConsumer(streamArn, 
consumerName);

Review Comment:
   Its a bit weird that we try to register the consumer here, but then fail it 
at line 198 without even checking if this attempt has succeeded. I would either 
move the check for attempts >= maxAttempts to the top of the method, or once 
registered here, check if its successful and return the consumer ARN. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to