Overriding the DataFetcher to return a custom GetRecordsResponseAdapter so that customers can have custom logic to send data to KinesisClientRecord (#1479)

This commit is contained in:
Abhi Gupta 2025-05-30 11:57:03 +05:30 committed by GitHub
parent 1ce6123a78
commit 37ae2f86be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 262 additions and 134 deletions

View file

@ -14,8 +14,6 @@
*/ */
package software.amazon.kinesis.retrieval; package software.amazon.kinesis.retrieval;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
/** /**
* Represents the result from the DataFetcher, and allows the receiver to accept a result * Represents the result from the DataFetcher, and allows the receiver to accept a result
*/ */
@ -25,7 +23,7 @@ public interface DataFetcherResult {
* *
* @return The result of the request, this can be null if the request failed. * @return The result of the request, this can be null if the request failed.
*/ */
GetRecordsResponse getResult(); GetRecordsResponseAdapter getResult();
/** /**
* Accepts the result, and advances the shard iterator. A result from the data fetcher must be accepted before any * Accepts the result, and advances the shard iterator. A result from the data fetcher must be accepted before any
@ -33,7 +31,7 @@ public interface DataFetcherResult {
* *
* @return the result of the request, this can be null if the request failed. * @return the result of the request, this can be null if the request failed.
*/ */
GetRecordsResponse accept(); GetRecordsResponseAdapter accept();
/** /**
* Indicates whether this result is at the end of the shard or not * Indicates whether this result is at the end of the shard or not

View file

@ -0,0 +1,55 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package software.amazon.kinesis.retrieval;
import java.util.List;
import software.amazon.awssdk.services.kinesis.model.ChildShard;
import software.amazon.kinesis.annotations.KinesisClientInternalApi;
@KinesisClientInternalApi
public interface GetRecordsResponseAdapter {
/**
* Returns the list of records retrieved from GetRecords.
* @return list of {@link KinesisClientRecord}
*/
List<KinesisClientRecord> records();
/**
* The number of milliseconds the response is from the tip of the stream.
* @return long
*/
Long millisBehindLatest();
/**
* Returns the list of child shards of the shard that was retrieved from GetRecords.
* @return list of {@link ChildShard}
*/
List<ChildShard> childShards();
/**
* Returns the next shard iterator to be used to retrieve next set of records.
* @return String
*/
String nextShardIterator();
/**
* Returns the request id of the GetRecords operation.
* @return String containing the request id
*/
String requestId();
}

View file

@ -16,7 +16,6 @@ package software.amazon.kinesis.retrieval;
import java.util.Optional; import java.util.Optional;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.retrieval.polling.DataFetcher; import software.amazon.kinesis.retrieval.polling.DataFetcher;
import software.amazon.kinesis.retrieval.polling.KinesisDataFetcher; import software.amazon.kinesis.retrieval.polling.KinesisDataFetcher;
@ -34,7 +33,7 @@ public interface GetRecordsRetrievalStrategy {
* @throws IllegalStateException * @throws IllegalStateException
* if the strategy has been shutdown. * if the strategy has been shutdown.
*/ */
GetRecordsResponse getRecords(int maxRecords); GetRecordsResponseAdapter getRecords(int maxRecords);
/** /**
* Releases any resources used by the strategy. Once the strategy is shutdown it is no longer safe to call * Releases any resources used by the strategy. Once the strategy is shutdown it is no longer safe to call

View file

@ -46,6 +46,27 @@ public class KinesisClientRecord {
private final boolean aggregated; private final boolean aggregated;
private final Schema schema; private final Schema schema;
protected KinesisClientRecord(
String sequenceNumber,
Instant approximateArrivalTimestamp,
ByteBuffer data,
String partitionKey,
EncryptionType encryptionType,
long subSequenceNumber,
String explicitHashKey,
boolean aggregated,
Schema schema) {
this.sequenceNumber = sequenceNumber;
this.approximateArrivalTimestamp = approximateArrivalTimestamp;
this.data = data;
this.partitionKey = partitionKey;
this.encryptionType = encryptionType;
this.subSequenceNumber = subSequenceNumber;
this.explicitHashKey = explicitHashKey;
this.aggregated = aggregated;
this.schema = schema;
}
public static KinesisClientRecord fromRecord(Record record) { public static KinesisClientRecord fromRecord(Record record) {
return KinesisClientRecord.builder() return KinesisClientRecord.builder()
.sequenceNumber(record.sequenceNumber()) .sequenceNumber(record.sequenceNumber())

View file

@ -0,0 +1,60 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package software.amazon.kinesis.retrieval;
import java.util.List;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import software.amazon.awssdk.services.kinesis.model.ChildShard;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.annotations.KinesisClientInternalApi;
@RequiredArgsConstructor
@EqualsAndHashCode
@KinesisClientInternalApi
public class KinesisGetRecordsResponseAdapter implements GetRecordsResponseAdapter {
private final GetRecordsResponse getRecordsResponse;
@Override
public List<KinesisClientRecord> records() {
return getRecordsResponse.records().stream()
.map(KinesisClientRecord::fromRecord)
.collect(Collectors.toList());
}
@Override
public Long millisBehindLatest() {
return getRecordsResponse.millisBehindLatest();
}
@Override
public List<ChildShard> childShards() {
return getRecordsResponse.childShards();
}
@Override
public String nextShardIterator() {
return getRecordsResponse.nextShardIterator();
}
@Override
public String requestId() {
return getRecordsResponse.responseMetadata().requestId();
}
}

View file

@ -32,9 +32,9 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.services.kinesis.model.ExpiredIteratorException; import software.amazon.awssdk.services.kinesis.model.ExpiredIteratorException;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.annotations.KinesisClientInternalApi; import software.amazon.kinesis.annotations.KinesisClientInternalApi;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
/** /**
@ -87,11 +87,11 @@ public class AsynchronousGetRecordsRetrievalStrategy implements GetRecordsRetrie
} }
@Override @Override
public GetRecordsResponse getRecords(final int maxRecords) { public GetRecordsResponseAdapter getRecords(final int maxRecords) {
if (executorService.isShutdown()) { if (executorService.isShutdown()) {
throw new IllegalStateException("Strategy has been shutdown"); throw new IllegalStateException("Strategy has been shutdown");
} }
GetRecordsResponse result = null; GetRecordsResponseAdapter result = null;
CompletionService<DataFetcherResult> completionService = completionServiceSupplier.get(); CompletionService<DataFetcherResult> completionService = completionServiceSupplier.get();
Set<Future<DataFetcherResult>> futures = new HashSet<>(); Set<Future<DataFetcherResult>> futures = new HashSet<>();
Callable<DataFetcherResult> retrieverCall = createRetrieverCallable(); Callable<DataFetcherResult> retrieverCall = createRetrieverCallable();

View file

@ -17,14 +17,13 @@ package software.amazon.kinesis.retrieval.polling;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.annotations.KinesisClientInternalApi; import software.amazon.kinesis.annotations.KinesisClientInternalApi;
import software.amazon.kinesis.common.InitialPositionInStreamExtended; import software.amazon.kinesis.common.InitialPositionInStreamExtended;
import software.amazon.kinesis.common.RequestDetails; import software.amazon.kinesis.common.RequestDetails;
import software.amazon.kinesis.lifecycle.events.ProcessRecordsInput; import software.amazon.kinesis.lifecycle.events.ProcessRecordsInput;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
import software.amazon.kinesis.retrieval.KinesisClientRecord; import software.amazon.kinesis.retrieval.KinesisClientRecord;
import software.amazon.kinesis.retrieval.RecordsPublisher; import software.amazon.kinesis.retrieval.RecordsPublisher;
@ -59,13 +58,11 @@ public class BlockingRecordsPublisher implements RecordsPublisher {
} }
public ProcessRecordsInput getNextResult() { public ProcessRecordsInput getNextResult() {
GetRecordsResponse getRecordsResult = getRecordsRetrievalStrategy.getRecords(maxRecordsPerCall); GetRecordsResponseAdapter getRecordsResult = getRecordsRetrievalStrategy.getRecords(maxRecordsPerCall);
final RequestDetails getRecordsRequestDetails = new RequestDetails( final RequestDetails getRecordsRequestDetails =
getRecordsResult.responseMetadata().requestId(), Instant.now().toString()); new RequestDetails(getRecordsResult.requestId(), Instant.now().toString());
setLastSuccessfulRequestDetails(getRecordsRequestDetails); setLastSuccessfulRequestDetails(getRecordsRequestDetails);
List<KinesisClientRecord> records = getRecordsResult.records().stream() List<KinesisClientRecord> records = getRecordsResult.records();
.map(KinesisClientRecord::fromRecord)
.collect(Collectors.toList());
return ProcessRecordsInput.builder() return ProcessRecordsInput.builder()
.records(records) .records(records)
.millisBehindLatest(getRecordsResult.millisBehindLatest()) .millisBehindLatest(getRecordsResult.millisBehindLatest())

View file

@ -15,13 +15,6 @@
package software.amazon.kinesis.retrieval.polling; package software.amazon.kinesis.retrieval.polling;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import lombok.NonNull;
import software.amazon.awssdk.services.kinesis.model.GetRecordsRequest;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.awssdk.services.kinesis.model.GetShardIteratorRequest;
import software.amazon.kinesis.common.InitialPositionInStreamExtended; import software.amazon.kinesis.common.InitialPositionInStreamExtended;
import software.amazon.kinesis.common.StreamIdentifier; import software.amazon.kinesis.common.StreamIdentifier;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
@ -76,39 +69,6 @@ public interface DataFetcher {
void resetIterator( void resetIterator(
String shardIterator, String sequenceNumber, InitialPositionInStreamExtended initialPositionInStream); String shardIterator, String sequenceNumber, InitialPositionInStreamExtended initialPositionInStream);
/**
* Retrieves the response based on the request.
*
* @param request the current get records request used to receive a response.
* @return GetRecordsResponse response for getRecords
*/
GetRecordsResponse getGetRecordsResponse(GetRecordsRequest request) throws Exception;
/**
* Retrieves the next get records request based on the current iterator.
*
* @param nextIterator specify the iterator to get the next record request
* @return {@link GetRecordsRequest}
*/
GetRecordsRequest getGetRecordsRequest(String nextIterator);
/**
* Gets the next iterator based on the request.
*
* @param request used to obtain the next shard iterator
* @return next iterator string
*/
String getNextIterator(GetShardIteratorRequest request)
throws ExecutionException, InterruptedException, TimeoutException;
/**
* Gets the next set of records based on the iterator.
*
* @param nextIterator specified shard iterator for getting the next set of records
* @return {@link GetRecordsResponse}
*/
GetRecordsResponse getRecords(@NonNull String nextIterator);
/** /**
* Get the current account and stream information. * Get the current account and stream information.
* *

View file

@ -46,8 +46,10 @@ import software.amazon.kinesis.metrics.MetricsUtil;
import software.amazon.kinesis.retrieval.AWSExceptionManager; import software.amazon.kinesis.retrieval.AWSExceptionManager;
import software.amazon.kinesis.retrieval.DataFetcherProviderConfig; import software.amazon.kinesis.retrieval.DataFetcherProviderConfig;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.IteratorBuilder; import software.amazon.kinesis.retrieval.IteratorBuilder;
import software.amazon.kinesis.retrieval.KinesisDataFetcherProviderConfig; import software.amazon.kinesis.retrieval.KinesisDataFetcherProviderConfig;
import software.amazon.kinesis.retrieval.KinesisGetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.RetryableRetrievalException; import software.amazon.kinesis.retrieval.RetryableRetrievalException;
import software.amazon.kinesis.retrieval.kpl.ExtendedSequenceNumber; import software.amazon.kinesis.retrieval.kpl.ExtendedSequenceNumber;
@ -163,17 +165,17 @@ public class KinesisDataFetcher implements DataFetcher {
final DataFetcherResult TERMINAL_RESULT = new DataFetcherResult() { final DataFetcherResult TERMINAL_RESULT = new DataFetcherResult() {
// CHECKSTYLE.ON: MemberName // CHECKSTYLE.ON: MemberName
@Override @Override
public GetRecordsResponse getResult() { public GetRecordsResponseAdapter getResult() {
return GetRecordsResponse.builder() return new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.millisBehindLatest(null) .millisBehindLatest(null)
.records(Collections.emptyList()) .records(Collections.emptyList())
.nextShardIterator(null) .nextShardIterator(null)
.childShards(Collections.emptyList()) .childShards(Collections.emptyList())
.build(); .build());
} }
@Override @Override
public GetRecordsResponse accept() { public GetRecordsResponseAdapter accept() {
isShardEndReached = true; isShardEndReached = true;
return getResult(); return getResult();
} }
@ -187,15 +189,15 @@ public class KinesisDataFetcher implements DataFetcher {
@Data @Data
class AdvancingResult implements DataFetcherResult { class AdvancingResult implements DataFetcherResult {
final GetRecordsResponse result; final GetRecordsResponseAdapter result;
@Override @Override
public GetRecordsResponse getResult() { public GetRecordsResponseAdapter getResult() {
return result; return result;
} }
@Override @Override
public GetRecordsResponse accept() { public GetRecordsResponseAdapter accept() {
nextIterator = result.nextShardIterator(); nextIterator = result.nextShardIterator();
if (result.records() != null && !result.records().isEmpty()) { if (result.records() != null && !result.records().isEmpty()) {
lastKnownSequenceNumber = Iterables.getLast(result.records()).sequenceNumber(); lastKnownSequenceNumber = Iterables.getLast(result.records()).sequenceNumber();
@ -331,8 +333,13 @@ public class KinesisDataFetcher implements DataFetcher {
this.initialPositionInStream = initialPositionInStream; this.initialPositionInStream = initialPositionInStream;
} }
@Override /**
public GetRecordsResponse getGetRecordsResponse(GetRecordsRequest request) * Retrieves the response based on the request.
*
* @param request the current get records request used to receive a response.
* @return GetRecordsResponse response for getRecords
*/
private GetRecordsResponseAdapter getGetRecordsResponse(GetRecordsRequest request)
throws ExecutionException, InterruptedException, TimeoutException { throws ExecutionException, InterruptedException, TimeoutException {
final GetRecordsResponse response = final GetRecordsResponse response =
FutureUtils.resolveOrCancelFuture(kinesisClient.getRecords(request), maxFutureWait); FutureUtils.resolveOrCancelFuture(kinesisClient.getRecords(request), maxFutureWait);
@ -342,11 +349,16 @@ public class KinesisDataFetcher implements DataFetcher {
+ ". childShards: " + response.childShards() + ". childShards: " + response.childShards()
+ ". Will retry GetRecords with the same nextIterator."); + ". Will retry GetRecords with the same nextIterator.");
} }
return response; return new KinesisGetRecordsResponseAdapter(response);
} }
@Override /**
public GetRecordsRequest getGetRecordsRequest(String nextIterator) { * Gets the next set of records based on the iterator.
*
* @param nextIterator specified shard iterator for getting the next set of records
* @return {@link GetRecordsResponseAdapter}
*/
private GetRecordsRequest getGetRecordsRequest(String nextIterator) {
GetRecordsRequest.Builder builder = KinesisRequestsBuilder.getRecordsRequestBuilder() GetRecordsRequest.Builder builder = KinesisRequestsBuilder.getRecordsRequestBuilder()
.shardIterator(nextIterator) .shardIterator(nextIterator)
.limit(maxRecords); .limit(maxRecords);
@ -354,16 +366,26 @@ public class KinesisDataFetcher implements DataFetcher {
return builder.build(); return builder.build();
} }
@Override /**
public String getNextIterator(GetShardIteratorRequest request) * Gets the next iterator based on the request.
*
* @param request used to obtain the next shard iterator
* @return next iterator string
*/
private String getNextIterator(GetShardIteratorRequest request)
throws ExecutionException, InterruptedException, TimeoutException { throws ExecutionException, InterruptedException, TimeoutException {
final GetShardIteratorResponse result = final GetShardIteratorResponse result =
FutureUtils.resolveOrCancelFuture(kinesisClient.getShardIterator(request), maxFutureWait); FutureUtils.resolveOrCancelFuture(kinesisClient.getShardIterator(request), maxFutureWait);
return result.shardIterator(); return result.shardIterator();
} }
@Override /**
public GetRecordsResponse getRecords(@NonNull final String nextIterator) { * Gets the next set of records based on the iterator.
*
* @param nextIterator specified shard iterator for getting the next set of records
* @return {@link GetRecordsResponse}
*/
private GetRecordsResponseAdapter getRecords(@NonNull final String nextIterator) {
GetRecordsRequest request = getGetRecordsRequest(nextIterator); GetRecordsRequest request = getGetRecordsRequest(nextIterator);
final MetricsScope metricsScope = MetricsUtil.createMetricsWithOperation(metricsFactory, OPERATION); final MetricsScope metricsScope = MetricsUtil.createMetricsWithOperation(metricsFactory, OPERATION);
@ -372,7 +394,7 @@ public class KinesisDataFetcher implements DataFetcher {
boolean success = false; boolean success = false;
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
try { try {
final GetRecordsResponse response = getGetRecordsResponse(request); final GetRecordsResponseAdapter response = getGetRecordsResponse(request);
success = true; success = true;
return response; return response;
} catch (ExecutionException e) { } catch (ExecutionException e) {

View file

@ -24,7 +24,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.AccessLevel; import lombok.AccessLevel;
@ -41,7 +40,6 @@ import org.reactivestreams.Subscription;
import software.amazon.awssdk.core.exception.SdkException; import software.amazon.awssdk.core.exception.SdkException;
import software.amazon.awssdk.services.cloudwatch.model.StandardUnit; import software.amazon.awssdk.services.cloudwatch.model.StandardUnit;
import software.amazon.awssdk.services.kinesis.model.ExpiredIteratorException; import software.amazon.awssdk.services.kinesis.model.ExpiredIteratorException;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.awssdk.services.kinesis.model.InvalidArgumentException; import software.amazon.awssdk.services.kinesis.model.InvalidArgumentException;
import software.amazon.awssdk.services.kinesis.model.ProvisionedThroughputExceededException; import software.amazon.awssdk.services.kinesis.model.ProvisionedThroughputExceededException;
import software.amazon.kinesis.annotations.KinesisClientInternalApi; import software.amazon.kinesis.annotations.KinesisClientInternalApi;
@ -55,6 +53,7 @@ import software.amazon.kinesis.metrics.MetricsScope;
import software.amazon.kinesis.metrics.MetricsUtil; import software.amazon.kinesis.metrics.MetricsUtil;
import software.amazon.kinesis.metrics.ThreadSafeMetricsDelegatingFactory; import software.amazon.kinesis.metrics.ThreadSafeMetricsDelegatingFactory;
import software.amazon.kinesis.retrieval.BatchUniqueIdentifier; import software.amazon.kinesis.retrieval.BatchUniqueIdentifier;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
import software.amazon.kinesis.retrieval.KinesisClientRecord; import software.amazon.kinesis.retrieval.KinesisClientRecord;
import software.amazon.kinesis.retrieval.RecordsDeliveryAck; import software.amazon.kinesis.retrieval.RecordsDeliveryAck;
@ -534,12 +533,11 @@ public class PrefetchRecordsPublisher implements RecordsPublisher {
if (publisherSession.prefetchCounters().shouldGetNewRecords()) { if (publisherSession.prefetchCounters().shouldGetNewRecords()) {
try { try {
sleepBeforeNextCall(); sleepBeforeNextCall();
GetRecordsResponse getRecordsResult = getRecordsRetrievalStrategy.getRecords(maxRecordsPerCall); GetRecordsResponseAdapter getRecordsResult =
getRecordsRetrievalStrategy.getRecords(maxRecordsPerCall);
lastSuccessfulCall = Instant.now(); lastSuccessfulCall = Instant.now();
final List<KinesisClientRecord> records = getRecordsResult.records().stream() final List<KinesisClientRecord> records = getRecordsResult.records();
.map(KinesisClientRecord::fromRecord)
.collect(Collectors.toList());
ProcessRecordsInput processRecordsInput = ProcessRecordsInput.builder() ProcessRecordsInput processRecordsInput = ProcessRecordsInput.builder()
.records(records) .records(records)
.millisBehindLatest(getRecordsResult.millisBehindLatest()) .millisBehindLatest(getRecordsResult.millisBehindLatest())

View file

@ -16,8 +16,8 @@ package software.amazon.kinesis.retrieval.polling;
import lombok.Data; import lombok.Data;
import lombok.NonNull; import lombok.NonNull;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.annotations.KinesisClientInternalApi; import software.amazon.kinesis.annotations.KinesisClientInternalApi;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
/** /**
@ -31,7 +31,7 @@ public class SynchronousGetRecordsRetrievalStrategy implements GetRecordsRetriev
private final DataFetcher dataFetcher; private final DataFetcher dataFetcher;
@Override @Override
public GetRecordsResponse getRecords(final int maxRecords) { public GetRecordsResponseAdapter getRecords(final int maxRecords) {
return dataFetcher.getRecords().accept(); return dataFetcher.getRecords().accept();
} }

View file

@ -38,6 +38,8 @@ import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.metrics.MetricsFactory; import software.amazon.kinesis.metrics.MetricsFactory;
import software.amazon.kinesis.metrics.NullMetricsFactory; import software.amazon.kinesis.metrics.NullMetricsFactory;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.KinesisGetRecordsResponseAdapter;
import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
@ -71,7 +73,7 @@ public class AsynchronousGetRecordsRetrievalStrategyIntegrationTest {
private KinesisAsyncClient kinesisClient; private KinesisAsyncClient kinesisClient;
private CompletionService<DataFetcherResult> completionService; private CompletionService<DataFetcherResult> completionService;
private GetRecordsResponse getRecordsResponse; private GetRecordsResponseAdapter getRecordsResponse;
private AsynchronousGetRecordsRetrievalStrategy getRecordsRetrivalStrategy; private AsynchronousGetRecordsRetrievalStrategy getRecordsRetrivalStrategy;
private KinesisDataFetcher dataFetcher; private KinesisDataFetcher dataFetcher;
@ -97,7 +99,8 @@ public class AsynchronousGetRecordsRetrievalStrategyIntegrationTest {
completionService = spy(new ExecutorCompletionService<DataFetcherResult>(executorService)); completionService = spy(new ExecutorCompletionService<DataFetcherResult>(executorService));
getRecordsRetrivalStrategy = new AsynchronousGetRecordsRetrievalStrategy( getRecordsRetrivalStrategy = new AsynchronousGetRecordsRetrievalStrategy(
dataFetcher, executorService, RETRY_GET_RECORDS_IN_SECONDS, completionServiceSupplier, "shardId-0001"); dataFetcher, executorService, RETRY_GET_RECORDS_IN_SECONDS, completionServiceSupplier, "shardId-0001");
getRecordsResponse = GetRecordsResponse.builder().build(); getRecordsResponse = new KinesisGetRecordsResponseAdapter(
GetRecordsResponse.builder().build());
when(completionServiceSupplier.get()).thenReturn(completionService); when(completionServiceSupplier.get()).thenReturn(completionService);
when(result.accept()).thenReturn(getRecordsResponse); when(result.accept()).thenReturn(getRecordsResponse);
@ -106,7 +109,7 @@ public class AsynchronousGetRecordsRetrievalStrategyIntegrationTest {
@Test @Test
public void oneRequestMultithreadTest() { public void oneRequestMultithreadTest() {
when(result.accept()).thenReturn(null); when(result.accept()).thenReturn(null);
GetRecordsResponse getRecordsResult = getRecordsRetrivalStrategy.getRecords(numberOfRecords); GetRecordsResponseAdapter getRecordsResult = getRecordsRetrivalStrategy.getRecords(numberOfRecords);
verify(dataFetcher, atLeast(getLeastNumberOfCalls())).getRecords(); verify(dataFetcher, atLeast(getLeastNumberOfCalls())).getRecords();
verify(executorService, atLeast(getLeastNumberOfCalls())).execute(any()); verify(executorService, atLeast(getLeastNumberOfCalls())).execute(any());
assertNull(getRecordsResult); assertNull(getRecordsResult);
@ -117,7 +120,7 @@ public class AsynchronousGetRecordsRetrievalStrategyIntegrationTest {
ExecutorCompletionService<DataFetcherResult> completionService1 = ExecutorCompletionService<DataFetcherResult> completionService1 =
spy(new ExecutorCompletionService<DataFetcherResult>(executorService)); spy(new ExecutorCompletionService<DataFetcherResult>(executorService));
when(completionServiceSupplier.get()).thenReturn(completionService1); when(completionServiceSupplier.get()).thenReturn(completionService1);
GetRecordsResponse getRecordsResult = getRecordsRetrivalStrategy.getRecords(numberOfRecords); GetRecordsResponseAdapter getRecordsResult = getRecordsRetrivalStrategy.getRecords(numberOfRecords);
verify(dataFetcher, atLeast(getLeastNumberOfCalls())).getRecords(); verify(dataFetcher, atLeast(getLeastNumberOfCalls())).getRecords();
verify(executorService, atLeast(getLeastNumberOfCalls())).execute(any()); verify(executorService, atLeast(getLeastNumberOfCalls())).execute(any());
assertThat(getRecordsResult, equalTo(getRecordsResponse)); assertThat(getRecordsResult, equalTo(getRecordsResponse));
@ -127,7 +130,7 @@ public class AsynchronousGetRecordsRetrievalStrategyIntegrationTest {
spy(new ExecutorCompletionService<DataFetcherResult>(executorService)); spy(new ExecutorCompletionService<DataFetcherResult>(executorService));
when(completionServiceSupplier.get()).thenReturn(completionService2); when(completionServiceSupplier.get()).thenReturn(completionService2);
getRecordsResult = getRecordsRetrivalStrategy.getRecords(numberOfRecords); getRecordsResult = getRecordsRetrivalStrategy.getRecords(numberOfRecords);
assertThat(getRecordsResult, nullValue(GetRecordsResponse.class)); assertThat(getRecordsResult, nullValue(GetRecordsResponseAdapter.class));
} }
@Test(expected = ExpiredIteratorException.class) @Test(expected = ExpiredIteratorException.class)

View file

@ -30,6 +30,8 @@ import org.mockito.runners.MockitoJUnitRunner;
import software.amazon.awssdk.services.kinesis.model.ExpiredIteratorException; import software.amazon.awssdk.services.kinesis.model.ExpiredIteratorException;
import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse; import software.amazon.awssdk.services.kinesis.model.GetRecordsResponse;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.KinesisGetRecordsResponseAdapter;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
@ -73,11 +75,12 @@ public class AsynchronousGetRecordsRetrievalStrategyTest {
@Mock @Mock
private DataFetcherResult dataFetcherResult; private DataFetcherResult dataFetcherResult;
private GetRecordsResponse expectedResponses; private GetRecordsResponseAdapter expectedResponses;
@Before @Before
public void before() { public void before() {
expectedResponses = GetRecordsResponse.builder().build(); expectedResponses = new KinesisGetRecordsResponseAdapter(
GetRecordsResponse.builder().build());
when(completionServiceSupplier.get()).thenReturn(completionService); when(completionServiceSupplier.get()).thenReturn(completionService);
when(dataFetcherResult.accept()).thenReturn(expectedResponses); when(dataFetcherResult.accept()).thenReturn(expectedResponses);
@ -93,7 +96,7 @@ public class AsynchronousGetRecordsRetrievalStrategyTest {
when(completionService.poll(anyLong(), any())).thenReturn(successfulFuture); when(completionService.poll(anyLong(), any())).thenReturn(successfulFuture);
when(successfulFuture.get()).thenReturn(dataFetcherResult); when(successfulFuture.get()).thenReturn(dataFetcherResult);
GetRecordsResponse result = strategy.getRecords(10); GetRecordsResponseAdapter result = strategy.getRecords(10);
verify(executorService).isShutdown(); verify(executorService).isShutdown();
verify(completionService).submit(any()); verify(completionService).submit(any());
@ -116,7 +119,7 @@ public class AsynchronousGetRecordsRetrievalStrategyTest {
when(successfulFuture.cancel(anyBoolean())).thenReturn(false); when(successfulFuture.cancel(anyBoolean())).thenReturn(false);
when(blockedFuture.cancel(anyBoolean())).thenReturn(true); when(blockedFuture.cancel(anyBoolean())).thenReturn(true);
GetRecordsResponse actualResults = strategy.getRecords(10); GetRecordsResponseAdapter actualResults = strategy.getRecords(10);
verify(completionService, times(2)).submit(any()); verify(completionService, times(2)).submit(any());
verify(completionService, times(2)).poll(eq(RETRY_GET_RECORDS_IN_SECONDS), eq(TimeUnit.SECONDS)); verify(completionService, times(2)).poll(eq(RETRY_GET_RECORDS_IN_SECONDS), eq(TimeUnit.SECONDS));
@ -156,7 +159,7 @@ public class AsynchronousGetRecordsRetrievalStrategyTest {
when(successfulFuture.cancel(anyBoolean())).thenReturn(false); when(successfulFuture.cancel(anyBoolean())).thenReturn(false);
when(blockedFuture.cancel(anyBoolean())).thenReturn(true); when(blockedFuture.cancel(anyBoolean())).thenReturn(true);
GetRecordsResponse actualResult = strategy.getRecords(10); GetRecordsResponseAdapter actualResult = strategy.getRecords(10);
verify(completionService, times(3)).submit(any()); verify(completionService, times(3)).submit(any());
verify(completionService, times(3)).poll(eq(RETRY_GET_RECORDS_IN_SECONDS), eq(TimeUnit.SECONDS)); verify(completionService, times(3)).poll(eq(RETRY_GET_RECORDS_IN_SECONDS), eq(TimeUnit.SECONDS));

View file

@ -55,7 +55,9 @@ import software.amazon.kinesis.metrics.MetricsFactory;
import software.amazon.kinesis.metrics.NullMetricsFactory; import software.amazon.kinesis.metrics.NullMetricsFactory;
import software.amazon.kinesis.processor.Checkpointer; import software.amazon.kinesis.processor.Checkpointer;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
import software.amazon.kinesis.retrieval.KinesisGetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.RetryableRetrievalException; import software.amazon.kinesis.retrieval.RetryableRetrievalException;
import static org.hamcrest.CoreMatchers.isA; import static org.hamcrest.CoreMatchers.isA;
@ -433,7 +435,7 @@ public class KinesisDataFetcherTest {
assertTrue(terminal.isShardEnd()); assertTrue(terminal.isShardEnd());
assertNotNull(terminal.getResult()); assertNotNull(terminal.getResult());
final GetRecordsResponse terminalResult = terminal.getResult(); final GetRecordsResponseAdapter terminalResult = terminal.getResult();
assertNotNull(terminalResult.records()); assertNotNull(terminalResult.records());
assertEquals(0, terminalResult.records().size()); assertEquals(0, terminalResult.records().size());
assertNull(terminalResult.nextShardIterator()); assertNull(terminalResult.nextShardIterator());
@ -540,12 +542,13 @@ public class KinesisDataFetcherTest {
private DataFetcherResult assertAdvanced( private DataFetcherResult assertAdvanced(
GetRecordsResponse expectedResult, String previousValue, String nextValue) { GetRecordsResponse expectedResult, String previousValue, String nextValue) {
DataFetcherResult acceptResult = kinesisDataFetcher.getRecords(); DataFetcherResult acceptResult = kinesisDataFetcher.getRecords();
assertEquals(expectedResult, acceptResult.getResult()); KinesisGetRecordsResponseAdapter expectedResultAdapter = new KinesisGetRecordsResponseAdapter(expectedResult);
assertEquals(expectedResultAdapter, acceptResult.getResult());
assertEquals(previousValue, kinesisDataFetcher.getNextIterator()); assertEquals(previousValue, kinesisDataFetcher.getNextIterator());
assertFalse(kinesisDataFetcher.isShardEndReached()); assertFalse(kinesisDataFetcher.isShardEndReached());
assertEquals(expectedResult, acceptResult.accept()); assertEquals(expectedResultAdapter, acceptResult.accept());
assertEquals(nextValue, kinesisDataFetcher.getNextIterator()); assertEquals(nextValue, kinesisDataFetcher.getNextIterator());
if (nextValue == null) { if (nextValue == null) {
assertTrue(kinesisDataFetcher.isShardEndReached()); assertTrue(kinesisDataFetcher.isShardEndReached());
@ -557,7 +560,8 @@ public class KinesisDataFetcherTest {
private DataFetcherResult assertNoAdvance(final GetRecordsResponse expectedResult, final String previousValue) { private DataFetcherResult assertNoAdvance(final GetRecordsResponse expectedResult, final String previousValue) {
assertEquals(previousValue, kinesisDataFetcher.getNextIterator()); assertEquals(previousValue, kinesisDataFetcher.getNextIterator());
DataFetcherResult noAcceptResult = kinesisDataFetcher.getRecords(); DataFetcherResult noAcceptResult = kinesisDataFetcher.getRecords();
assertEquals(expectedResult, noAcceptResult.getResult()); KinesisGetRecordsResponseAdapter expectedResultAdapter = new KinesisGetRecordsResponseAdapter(expectedResult);
assertEquals(expectedResultAdapter, noAcceptResult.getResult());
assertEquals(previousValue, kinesisDataFetcher.getNextIterator()); assertEquals(previousValue, kinesisDataFetcher.getNextIterator());

View file

@ -46,7 +46,9 @@ import software.amazon.kinesis.lifecycle.events.ProcessRecordsInput;
import software.amazon.kinesis.metrics.MetricsFactory; import software.amazon.kinesis.metrics.MetricsFactory;
import software.amazon.kinesis.metrics.NullMetricsFactory; import software.amazon.kinesis.metrics.NullMetricsFactory;
import software.amazon.kinesis.retrieval.DataFetcherResult; import software.amazon.kinesis.retrieval.DataFetcherResult;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
import software.amazon.kinesis.retrieval.KinesisGetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.RecordsRetrieved; import software.amazon.kinesis.retrieval.RecordsRetrieved;
import software.amazon.kinesis.retrieval.ThrottlingReporter; import software.amazon.kinesis.retrieval.ThrottlingReporter;
import software.amazon.kinesis.retrieval.kpl.ExtendedSequenceNumber; import software.amazon.kinesis.retrieval.kpl.ExtendedSequenceNumber;
@ -305,11 +307,12 @@ public class PrefetchRecordsPublisherIntegrationTest {
@Override @Override
public DataFetcherResult getRecords() { public DataFetcherResult getRecords() {
GetRecordsResponse getRecordsResult = GetRecordsResponse.builder() GetRecordsResponseAdapter getRecordsResult =
new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(new ArrayList<>(records)) .records(new ArrayList<>(records))
.nextShardIterator(nextShardIterator) .nextShardIterator(nextShardIterator)
.millisBehindLatest(1000L) .millisBehindLatest(1000L)
.build(); .build());
return new AdvancingResult(getRecordsResult); return new AdvancingResult(getRecordsResult);
} }

View file

@ -66,8 +66,10 @@ import software.amazon.kinesis.leases.ShardObjectHelper;
import software.amazon.kinesis.lifecycle.ShardConsumerNotifyingSubscriber; import software.amazon.kinesis.lifecycle.ShardConsumerNotifyingSubscriber;
import software.amazon.kinesis.lifecycle.events.ProcessRecordsInput; import software.amazon.kinesis.lifecycle.events.ProcessRecordsInput;
import software.amazon.kinesis.metrics.NullMetricsFactory; import software.amazon.kinesis.metrics.NullMetricsFactory;
import software.amazon.kinesis.retrieval.GetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy; import software.amazon.kinesis.retrieval.GetRecordsRetrievalStrategy;
import software.amazon.kinesis.retrieval.KinesisClientRecord; import software.amazon.kinesis.retrieval.KinesisClientRecord;
import software.amazon.kinesis.retrieval.KinesisGetRecordsResponseAdapter;
import software.amazon.kinesis.retrieval.RecordsPublisher; import software.amazon.kinesis.retrieval.RecordsPublisher;
import software.amazon.kinesis.retrieval.RecordsRetrieved; import software.amazon.kinesis.retrieval.RecordsRetrieved;
import software.amazon.kinesis.retrieval.RetryableRetrievalException; import software.amazon.kinesis.retrieval.RetryableRetrievalException;
@ -136,7 +138,7 @@ public class PrefetchRecordsPublisherTest {
private ExecutorService executorService; private ExecutorService executorService;
private LinkedBlockingQueue<PrefetchRecordsPublisher.PrefetchRecordsRetrieved> spyQueue; private LinkedBlockingQueue<PrefetchRecordsPublisher.PrefetchRecordsRetrieved> spyQueue;
private PrefetchRecordsPublisher getRecordsCache; private PrefetchRecordsPublisher getRecordsCache;
private GetRecordsResponse getRecordsResponse; private GetRecordsResponseAdapter getRecordsResponse;
private Record record; private Record record;
@Before @Before
@ -147,11 +149,11 @@ public class PrefetchRecordsPublisherTest {
getRecordsCache = createPrefetchRecordsPublisher(0L); getRecordsCache = createPrefetchRecordsPublisher(0L);
spyQueue = spy(getRecordsCache.getPublisherSession().prefetchRecordsQueue()); spyQueue = spy(getRecordsCache.getPublisherSession().prefetchRecordsQueue());
records = spy(new ArrayList<>()); records = spy(new ArrayList<>());
getRecordsResponse = GetRecordsResponse.builder() getRecordsResponse = new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(records) .records(records)
.nextShardIterator(NEXT_SHARD_ITERATOR) .nextShardIterator(NEXT_SHARD_ITERATOR)
.childShards(Collections.emptyList()) .childShards(Collections.emptyList())
.build(); .build());
when(getRecordsRetrievalStrategy.getRecords(eq(MAX_RECORDS_PER_CALL))).thenReturn(getRecordsResponse); when(getRecordsRetrievalStrategy.getRecords(eq(MAX_RECORDS_PER_CALL))).thenReturn(getRecordsResponse);
} }
@ -283,8 +285,8 @@ public class PrefetchRecordsPublisherTest {
public void testGetRecordsWithInvalidResponse() { public void testGetRecordsWithInvalidResponse() {
record = Record.builder().data(createByteBufferWithSize(SIZE_512_KB)).build(); record = Record.builder().data(createByteBufferWithSize(SIZE_512_KB)).build();
GetRecordsResponse response = GetRecordsResponseAdapter response = new KinesisGetRecordsResponseAdapter(
GetRecordsResponse.builder().records(records).build(); GetRecordsResponse.builder().records(records).build());
when(getRecordsRetrievalStrategy.getRecords(eq(MAX_RECORDS_PER_CALL))).thenReturn(response); when(getRecordsRetrievalStrategy.getRecords(eq(MAX_RECORDS_PER_CALL))).thenReturn(response);
when(dataFetcher.isShardEndReached()).thenReturn(false); when(dataFetcher.isShardEndReached()).thenReturn(false);
@ -319,10 +321,10 @@ public class PrefetchRecordsPublisherTest {
childShards.add(leftChild); childShards.add(leftChild);
childShards.add(rightChild); childShards.add(rightChild);
GetRecordsResponse response = GetRecordsResponse.builder() GetRecordsResponseAdapter response = new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(records) .records(records)
.childShards(childShards) .childShards(childShards)
.build(); .build());
when(getRecordsRetrievalStrategy.getRecords(eq(MAX_RECORDS_PER_CALL))).thenReturn(response); when(getRecordsRetrievalStrategy.getRecords(eq(MAX_RECORDS_PER_CALL))).thenReturn(response);
when(dataFetcher.isShardEndReached()).thenReturn(true); when(dataFetcher.isShardEndReached()).thenReturn(true);
@ -417,13 +419,13 @@ public class PrefetchRecordsPublisherTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void testRequestRecordsOnSubscriptionAfterShutdown() { public void testRequestRecordsOnSubscriptionAfterShutdown() {
GetRecordsResponse response = GetRecordsResponse.builder() GetRecordsResponseAdapter response = new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(Record.builder() .records(Record.builder()
.data(SdkBytes.fromByteArray(new byte[] {1, 2, 3})) .data(SdkBytes.fromByteArray(new byte[] {1, 2, 3}))
.sequenceNumber("123") .sequenceNumber("123")
.build()) .build())
.nextShardIterator(NEXT_SHARD_ITERATOR) .nextShardIterator(NEXT_SHARD_ITERATOR)
.build(); .build());
when(getRecordsRetrievalStrategy.getRecords(anyInt())).thenReturn(response); when(getRecordsRetrievalStrategy.getRecords(anyInt())).thenReturn(response);
getRecordsCache.start(sequenceNumber, initialPosition); getRecordsCache.start(sequenceNumber, initialPosition);
@ -482,11 +484,11 @@ public class PrefetchRecordsPublisherTest {
@Test @Test
public void testRetryableRetrievalExceptionContinues() { public void testRetryableRetrievalExceptionContinues() {
GetRecordsResponse response = GetRecordsResponse.builder() GetRecordsResponseAdapter response = new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.millisBehindLatest(100L) .millisBehindLatest(100L)
.records(Collections.emptyList()) .records(Collections.emptyList())
.nextShardIterator(NEXT_SHARD_ITERATOR) .nextShardIterator(NEXT_SHARD_ITERATOR)
.build(); .build());
when(getRecordsRetrievalStrategy.getRecords(anyInt())) when(getRecordsRetrievalStrategy.getRecords(anyInt()))
.thenThrow(new RetryableRetrievalException("Timeout", new TimeoutException("Timeout"))) .thenThrow(new RetryableRetrievalException("Timeout", new TimeoutException("Timeout")))
.thenReturn(response); .thenReturn(response);
@ -526,13 +528,14 @@ public class PrefetchRecordsPublisherTest {
// //
final int[] sequenceNumberInResponse = {0}; final int[] sequenceNumberInResponse = {0};
when(getRecordsRetrievalStrategy.getRecords(anyInt())).thenAnswer(i -> GetRecordsResponse.builder() when(getRecordsRetrievalStrategy.getRecords(anyInt()))
.thenAnswer(i -> new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(Record.builder() .records(Record.builder()
.data(SdkBytes.fromByteArray(new byte[] {1, 2, 3})) .data(SdkBytes.fromByteArray(new byte[] {1, 2, 3}))
.sequenceNumber(++sequenceNumberInResponse[0] + "") .sequenceNumber(++sequenceNumberInResponse[0] + "")
.build()) .build())
.nextShardIterator(NEXT_SHARD_ITERATOR) .nextShardIterator(NEXT_SHARD_ITERATOR)
.build()); .build()));
getRecordsCache.start(sequenceNumber, initialPosition); getRecordsCache.start(sequenceNumber, initialPosition);
@ -627,13 +630,13 @@ public class PrefetchRecordsPublisherTest {
// //
// This test is to verify that the data consumption is not stuck in the case of an failed event delivery // This test is to verify that the data consumption is not stuck in the case of an failed event delivery
// to the subscriber. // to the subscriber.
GetRecordsResponse response = GetRecordsResponse.builder() GetRecordsResponseAdapter response = new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(Record.builder() .records(Record.builder()
.data(SdkBytes.fromByteArray(new byte[] {1, 2, 3})) .data(SdkBytes.fromByteArray(new byte[] {1, 2, 3}))
.sequenceNumber("123") .sequenceNumber("123")
.build()) .build())
.nextShardIterator(NEXT_SHARD_ITERATOR) .nextShardIterator(NEXT_SHARD_ITERATOR)
.build(); .build());
when(getRecordsRetrievalStrategy.getRecords(anyInt())).thenReturn(response); when(getRecordsRetrievalStrategy.getRecords(anyInt())).thenReturn(response);
getRecordsCache.start(sequenceNumber, initialPosition); getRecordsCache.start(sequenceNumber, initialPosition);
@ -710,7 +713,7 @@ public class PrefetchRecordsPublisherTest {
@Test @Test
public void testResetClearsRemainingData() { public void testResetClearsRemainingData() {
List<GetRecordsResponse> responses = Stream.iterate(0, i -> i + 1) List<GetRecordsResponseAdapter> responses = Stream.iterate(0, i -> i + 1)
.limit(10) .limit(10)
.map(i -> { .map(i -> {
Record record = Record.builder() Record record = Record.builder()
@ -720,10 +723,10 @@ public class PrefetchRecordsPublisherTest {
.approximateArrivalTimestamp(Instant.now()) .approximateArrivalTimestamp(Instant.now())
.build(); .build();
String nextIterator = "shard-iter-" + (i + 1); String nextIterator = "shard-iter-" + (i + 1);
return GetRecordsResponse.builder() return new KinesisGetRecordsResponseAdapter(GetRecordsResponse.builder()
.records(record) .records(record)
.nextShardIterator(nextIterator) .nextShardIterator(nextIterator)
.build(); .build());
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -778,7 +781,8 @@ public class PrefetchRecordsPublisherTest {
try { try {
// return a valid response to cause `lastSuccessfulCall` to initialize // return a valid response to cause `lastSuccessfulCall` to initialize
when(getRecordsRetrievalStrategy.getRecords(anyInt())) when(getRecordsRetrievalStrategy.getRecords(anyInt()))
.thenReturn(GetRecordsResponse.builder().build()); .thenReturn(new KinesisGetRecordsResponseAdapter(
GetRecordsResponse.builder().build()));
blockUntilRecordsAvailable(); blockUntilRecordsAvailable();
} catch (RuntimeException re) { } catch (RuntimeException re) {
Assert.fail("first call should succeed"); Assert.fail("first call should succeed");
@ -803,7 +807,8 @@ public class PrefetchRecordsPublisherTest {
public void testProvisionedThroughputExceededExceptionReporter() { public void testProvisionedThroughputExceededExceptionReporter() {
when(getRecordsRetrievalStrategy.getRecords(anyInt())) when(getRecordsRetrievalStrategy.getRecords(anyInt()))
.thenThrow(ProvisionedThroughputExceededException.builder().build()) .thenThrow(ProvisionedThroughputExceededException.builder().build())
.thenReturn(GetRecordsResponse.builder().build()); .thenReturn(new KinesisGetRecordsResponseAdapter(
GetRecordsResponse.builder().build()));
getRecordsCache.start(sequenceNumber, initialPosition); getRecordsCache.start(sequenceNumber, initialPosition);
@ -822,20 +827,20 @@ public class PrefetchRecordsPublisherTest {
return getRecordsCache.getPublisherSession().evictPublishedRecordAndUpdateDemand("shardId"); return getRecordsCache.getPublisherSession().evictPublishedRecordAndUpdateDemand("shardId");
} }
private static class RetrieverAnswer implements Answer<GetRecordsResponse> { private static class RetrieverAnswer implements Answer<GetRecordsResponseAdapter> {
private final List<GetRecordsResponse> responses; private final List<GetRecordsResponseAdapter> responses;
private Iterator<GetRecordsResponse> iterator; private Iterator<GetRecordsResponseAdapter> iterator;
public RetrieverAnswer(List<GetRecordsResponse> responses) { public RetrieverAnswer(List<GetRecordsResponseAdapter> responses) {
this.responses = responses; this.responses = responses;
this.iterator = responses.iterator(); this.iterator = responses.iterator();
} }
public void resetIteratorTo(String nextIterator) { public void resetIteratorTo(String nextIterator) {
Iterator<GetRecordsResponse> newIterator = responses.iterator(); Iterator<GetRecordsResponseAdapter> newIterator = responses.iterator();
while (newIterator.hasNext()) { while (newIterator.hasNext()) {
GetRecordsResponse current = newIterator.next(); GetRecordsResponseAdapter current = newIterator.next();
if (StringUtils.equals(nextIterator, current.nextShardIterator())) { if (StringUtils.equals(nextIterator, current.nextShardIterator())) {
if (!newIterator.hasNext()) { if (!newIterator.hasNext()) {
iterator = responses.iterator(); iterator = responses.iterator();
@ -849,8 +854,8 @@ public class PrefetchRecordsPublisherTest {
} }
@Override @Override
public GetRecordsResponse answer(InvocationOnMock invocation) { public GetRecordsResponseAdapter answer(InvocationOnMock invocation) {
GetRecordsResponse response = iterator.next(); GetRecordsResponseAdapter response = iterator.next();
if (!iterator.hasNext()) { if (!iterator.hasNext()) {
iterator = responses.iterator(); iterator = responses.iterator();
} }