Migrate KinesisProxy to ListShardsWithFilter for empty lease table case
This commit is contained in:
parent
e1111d487e
commit
c7cd2f1e75
5 changed files with 118 additions and 17 deletions
|
|
@ -26,6 +26,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.amazonaws.services.kinesis.model.ShardFilter;
|
||||||
|
import com.amazonaws.services.kinesis.model.ShardFilterType;
|
||||||
import com.amazonaws.util.CollectionUtils;
|
import com.amazonaws.util.CollectionUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
@ -130,7 +132,14 @@ class KinesisShardSyncer implements ShardSyncer {
|
||||||
boolean cleanupLeasesOfCompletedShards, boolean ignoreUnexpectedChildShards)
|
boolean cleanupLeasesOfCompletedShards, boolean ignoreUnexpectedChildShards)
|
||||||
throws DependencyException, InvalidStateException, ProvisionedThroughputException,
|
throws DependencyException, InvalidStateException, ProvisionedThroughputException,
|
||||||
KinesisClientLibIOException {
|
KinesisClientLibIOException {
|
||||||
List<Shard> latestShards = getShardList(kinesisProxy);
|
|
||||||
|
// In the case where the lease table is empty, we want to synchronize the minimal amount of shards possible
|
||||||
|
// based on the given initial position.
|
||||||
|
// TODO: Implement shard list filtering on non-empty lease table case
|
||||||
|
final List<Shard> latestShards = leaseManager.isLeaseTableEmpty()
|
||||||
|
? getShardListAtInitialPosition(kinesisProxy, initialPosition)
|
||||||
|
: getCompleteShardList(kinesisProxy);
|
||||||
|
|
||||||
syncShardLeases(kinesisProxy, leaseManager, initialPosition, cleanupLeasesOfCompletedShards, ignoreUnexpectedChildShards, latestShards);
|
syncShardLeases(kinesisProxy, leaseManager, initialPosition, cleanupLeasesOfCompletedShards, ignoreUnexpectedChildShards, latestShards);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,7 +165,7 @@ class KinesisShardSyncer implements ShardSyncer {
|
||||||
KinesisClientLibIOException {
|
KinesisClientLibIOException {
|
||||||
List<Shard> shards;
|
List<Shard> shards;
|
||||||
if(CollectionUtils.isNullOrEmpty(latestShards)) {
|
if(CollectionUtils.isNullOrEmpty(latestShards)) {
|
||||||
shards = getShardList(kinesisProxy);
|
shards = getCompleteShardList(kinesisProxy);
|
||||||
} else {
|
} else {
|
||||||
shards = latestShards;
|
shards = latestShards;
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +354,7 @@ class KinesisShardSyncer implements ShardSyncer {
|
||||||
return shardIdToChildShardIdsMap;
|
return shardIdToChildShardIdsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Shard> getShardList(IKinesisProxy kinesisProxy) throws KinesisClientLibIOException {
|
private List<Shard> getCompleteShardList(IKinesisProxy kinesisProxy) throws KinesisClientLibIOException {
|
||||||
List<Shard> shards = kinesisProxy.getShardList();
|
List<Shard> shards = kinesisProxy.getShardList();
|
||||||
if (shards == null) {
|
if (shards == null) {
|
||||||
throw new KinesisClientLibIOException(
|
throw new KinesisClientLibIOException(
|
||||||
|
|
@ -354,6 +363,44 @@ class KinesisShardSyncer implements ShardSyncer {
|
||||||
return shards;
|
return shards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Shard> getShardListAtInitialPosition(IKinesisProxy kinesisProxy,
|
||||||
|
InitialPositionInStreamExtended initialPosition)
|
||||||
|
throws KinesisClientLibIOException {
|
||||||
|
|
||||||
|
final ShardFilter shardFilter = getShardFilterAtInitialPosition(initialPosition);
|
||||||
|
final List<Shard> shards = kinesisProxy.getShardListWithFilter(shardFilter);
|
||||||
|
|
||||||
|
if (shards == null) {
|
||||||
|
throw new KinesisClientLibIOException(
|
||||||
|
"Stream is not in ACTIVE OR UPDATING state - will retry getting the shard list.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return shards;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShardFilter getShardFilterAtInitialPosition(InitialPositionInStreamExtended initialPosition) {
|
||||||
|
ShardFilter shardFilter = new ShardFilter();
|
||||||
|
|
||||||
|
switch (initialPosition.getInitialPositionInStream()) {
|
||||||
|
case LATEST:
|
||||||
|
shardFilter = shardFilter.withType(ShardFilterType.AT_LATEST);
|
||||||
|
break;
|
||||||
|
case TRIM_HORIZON:
|
||||||
|
shardFilter = shardFilter.withType(ShardFilterType.AT_TRIM_HORIZON);
|
||||||
|
break;
|
||||||
|
case AT_TIMESTAMP:
|
||||||
|
shardFilter = shardFilter.withType(ShardFilterType.AT_TIMESTAMP)
|
||||||
|
.withTimestamp(initialPosition.getTimestamp());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(initialPosition.getInitialPositionInStream()
|
||||||
|
+ " is not a supported initial position in a Kinesis stream. Supported initial positions are"
|
||||||
|
+ " AT_LATEST, AT_TRIM_HORIZON, and AT_TIMESTAMP.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return shardFilter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine new leases to create and their initial checkpoint.
|
* Determine new leases to create and their initial checkpoint.
|
||||||
* Note: Package level access only for testing purposes.
|
* Note: Package level access only for testing purposes.
|
||||||
|
|
@ -630,7 +677,7 @@ class KinesisShardSyncer implements ShardSyncer {
|
||||||
if (!garbageLeases.isEmpty()) {
|
if (!garbageLeases.isEmpty()) {
|
||||||
LOG.info("Found " + garbageLeases.size() + " candidate leases for cleanup. Refreshing list of"
|
LOG.info("Found " + garbageLeases.size() + " candidate leases for cleanup. Refreshing list of"
|
||||||
+ " Kinesis shards to pick up recent/latest shards");
|
+ " Kinesis shards to pick up recent/latest shards");
|
||||||
List<Shard> currentShardList = getShardList(kinesisProxy);
|
List<Shard> currentShardList = getCompleteShardList(kinesisProxy);
|
||||||
Set<String> currentKinesisShardIds = new HashSet<>();
|
Set<String> currentKinesisShardIds = new HashSet<>();
|
||||||
for (Shard shard : currentShardList) {
|
for (Shard shard : currentShardList) {
|
||||||
currentKinesisShardIds.add(shard.getShardId());
|
currentKinesisShardIds.add(shard.getShardId());
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import com.amazonaws.services.kinesis.model.InvalidArgumentException;
|
||||||
import com.amazonaws.services.kinesis.model.PutRecordResult;
|
import com.amazonaws.services.kinesis.model.PutRecordResult;
|
||||||
import com.amazonaws.services.kinesis.model.ResourceNotFoundException;
|
import com.amazonaws.services.kinesis.model.ResourceNotFoundException;
|
||||||
import com.amazonaws.services.kinesis.model.Shard;
|
import com.amazonaws.services.kinesis.model.Shard;
|
||||||
|
import com.amazonaws.services.kinesis.model.ShardFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kinesis proxy interface. Operates on a single stream (set up at initialization).
|
* Kinesis proxy interface. Operates on a single stream (set up at initialization).
|
||||||
|
|
@ -78,6 +79,17 @@ public interface IKinesisProxy {
|
||||||
*/
|
*/
|
||||||
List<Shard> getShardList() throws ResourceNotFoundException;
|
List<Shard> getShardList() throws ResourceNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a subset shards defined for the stream using a filter on the ListShards API. This can be used to
|
||||||
|
* discover new shards and consume data from them, while limiting the total number of shards returned for
|
||||||
|
* performance or efficiency reasons.
|
||||||
|
*
|
||||||
|
* @param shardFilter currently supported filter types are AT_LATEST, AT_TRIM_HORIZON, AT_TIMESTAMP.
|
||||||
|
* @return List of all shards in the Kinesis stream.
|
||||||
|
* @throws ResourceNotFoundException The Kinesis stream was not found.
|
||||||
|
*/
|
||||||
|
List<Shard> getShardListWithFilter(ShardFilter shardFilter) throws ResourceNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to verify during ShardConsumer shutdown if the provided shardId is for a shard that has been closed.
|
* Used to verify during ShardConsumer shutdown if the provided shardId is for a shard that has been closed.
|
||||||
* @param shardId Id of the shard that needs to be verified.
|
* @param shardId Id of the shard that needs to be verified.
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.amazonaws.services.kinesis.model.ShardFilter;
|
||||||
import com.amazonaws.util.CollectionUtils;
|
import com.amazonaws.util.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
@ -309,7 +310,7 @@ public class KinesisProxy implements IKinesisProxyExtended {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListShardsResult listShards(final String nextToken) {
|
private ListShardsResult listShards(final ShardFilter shardFilter, final String nextToken) {
|
||||||
final ListShardsRequest request = new ListShardsRequest();
|
final ListShardsRequest request = new ListShardsRequest();
|
||||||
request.setRequestCredentials(credentialsProvider.getCredentials());
|
request.setRequestCredentials(credentialsProvider.getCredentials());
|
||||||
if (StringUtils.isEmpty(nextToken)) {
|
if (StringUtils.isEmpty(nextToken)) {
|
||||||
|
|
@ -317,6 +318,11 @@ public class KinesisProxy implements IKinesisProxyExtended {
|
||||||
} else {
|
} else {
|
||||||
request.setNextToken(nextToken);
|
request.setNextToken(nextToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shardFilter != null) {
|
||||||
|
request.setShardFilter(shardFilter);
|
||||||
|
}
|
||||||
|
|
||||||
ListShardsResult result = null;
|
ListShardsResult result = null;
|
||||||
LimitExceededException lastException = null;
|
LimitExceededException lastException = null;
|
||||||
int remainingRetries = this.maxListShardsRetryAttempts;
|
int remainingRetries = this.maxListShardsRetryAttempts;
|
||||||
|
|
@ -429,6 +435,14 @@ public class KinesisProxy implements IKinesisProxyExtended {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<Shard> getShardList() {
|
public synchronized List<Shard> getShardList() {
|
||||||
|
return getShardListWithFilter(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized List<Shard> getShardListWithFilter(ShardFilter shardFilter) {
|
||||||
if (shardIterationState == null) {
|
if (shardIterationState == null) {
|
||||||
shardIterationState = new ShardIterationState();
|
shardIterationState = new ShardIterationState();
|
||||||
}
|
}
|
||||||
|
|
@ -438,7 +452,7 @@ public class KinesisProxy implements IKinesisProxyExtended {
|
||||||
String nextToken = null;
|
String nextToken = null;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
result = listShards(nextToken);
|
result = listShards(shardFilter, nextToken);
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import com.amazonaws.services.kinesis.model.ResourceNotFoundException;
|
||||||
import com.amazonaws.services.kinesis.model.Shard;
|
import com.amazonaws.services.kinesis.model.Shard;
|
||||||
import com.amazonaws.services.kinesis.metrics.impl.MetricsHelper;
|
import com.amazonaws.services.kinesis.metrics.impl.MetricsHelper;
|
||||||
import com.amazonaws.services.kinesis.metrics.interfaces.MetricsLevel;
|
import com.amazonaws.services.kinesis.metrics.interfaces.MetricsLevel;
|
||||||
|
import com.amazonaws.services.kinesis.model.ShardFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IKinesisProxy implementation that wraps another implementation and collects metrics.
|
* IKinesisProxy implementation that wraps another implementation and collects metrics.
|
||||||
|
|
@ -179,6 +180,22 @@ public class MetricsCollectingKinesisProxyDecorator implements IKinesisProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Shard> getShardListWithFilter(ShardFilter shardFilter) throws ResourceNotFoundException {
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
boolean success = false;
|
||||||
|
try {
|
||||||
|
List<Shard> response = other.getShardListWithFilter(shardFilter);
|
||||||
|
success = true;
|
||||||
|
return response;
|
||||||
|
} finally {
|
||||||
|
MetricsHelper.addSuccessAndLatency(getShardListMetric, startTime, success, MetricsLevel.DETAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.amazonaws.services.kinesis.model.ShardFilter;
|
||||||
import com.amazonaws.util.CollectionUtils;
|
import com.amazonaws.util.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
|
@ -425,6 +426,16 @@ public class KinesisLocalFileProxy implements IKinesisProxy {
|
||||||
return shards;
|
return shards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<Shard> getShardListWithFilter(ShardFilter shardFilter) throws ResourceNotFoundException {
|
||||||
|
List<Shard> shards = new LinkedList<Shard>();
|
||||||
|
shards.addAll(shardList);
|
||||||
|
return shards;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue