package com.amazonaws.services.kinesis; import java.net.NetworkInterface; import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.regions.Region; import com.amazonaws.regions.Regions; import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorFactory; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.InitialPositionInStream; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker; public class ManagedConsumer { private static final String version = ".9.0"; private static final Log LOG = LogFactory.getLog(ManagedConsumer.class); private String streamName, appName, regionName, environmentName, positionInStream, kinesisEndpoint; private AWSCredentialsProvider credentialsProvider; private InitialPositionInStream streamPosition; private int failuresToTolerate = -1; private int maxRecords = -1; private KinesisClientLibConfiguration config; private boolean isConfigured = false; private ManagedClientProcessor templateProcessor; public ManagedConsumer(String streamName, String appName, ManagedClientProcessor templateProcessor) { this.streamName = streamName; this.appName = appName; this.templateProcessor = templateProcessor; } public int run() throws Exception { configure(); System.out.println(String.format("Starting %s", appName)); LOG.info(String.format("Running %s to process stream %s", appName, streamName)); IRecordProcessorFactory recordProcessorFactory = new ManagedClientProcessorFactory( this.templateProcessor); Worker worker = new Worker(recordProcessorFactory, this.config); int exitCode = 0; int failures = 0; // run the worker, tolerating as many failures as is configured while (failures < failuresToTolerate || failuresToTolerate == -1) { try { worker.run(); } catch (Throwable t) { LOG.error("Caught throwable while processing data.", t); failures++; if (failures < failuresToTolerate) { LOG.error("Restarting..."); } exitCode = 1; } } return exitCode; } private void assertThat(boolean condition, String message) throws Exception { if (!condition) { throw new InvalidConfigurationException(message); } } private void validateConfig() throws InvalidConfigurationException { try { assertThat(this.streamName != null, "Must Specify a Stream Name"); assertThat(this.appName != null, "Must Specify an Application Name"); } catch (Exception e) { throw new InvalidConfigurationException(e.getMessage()); } } public void configure() throws Exception { if (!isConfigured) { validateConfig(); try { String userAgent = "AWSKinesisManagedConsumer/" + this.version; if (this.positionInStream != null) { streamPosition = InitialPositionInStream.valueOf(this.positionInStream); } else { streamPosition = InitialPositionInStream.LATEST; } // append the environment name to the application name if (environmentName != null) { appName = String.format("%s-%s", appName, environmentName); } // ensure the JVM will refresh the cached IP values of AWS // resources // (e.g. service endpoints). java.security.Security.setProperty("networkaddress.cache.ttl", "60"); String workerId = NetworkInterface.getNetworkInterfaces() + ":" + UUID.randomUUID(); LOG.info("Using Worker ID: " + workerId); // obtain credentials using the default provider chain or the // credentials provider supplied AWSCredentialsProvider credentialsProvider = this.credentialsProvider == null ? new DefaultAWSCredentialsProviderChain() : this.credentialsProvider; LOG.info("Using credentials with Access Key ID: " + credentialsProvider.getCredentials().getAWSAccessKeyId()); config = new KinesisClientLibConfiguration(appName, streamName, credentialsProvider, workerId).withInitialPositionInStream(streamPosition).withKinesisEndpoint( kinesisEndpoint); config.getKinesisClientConfiguration().setUserAgent(userAgent); if (regionName != null) { Region region = Region.getRegion(Regions.fromName(regionName)); config.withRegionName(region.getName()); } if (this.maxRecords != -1) config.withMaxRecords(maxRecords); if (this.positionInStream != null) config.withInitialPositionInStream(InitialPositionInStream.valueOf(this.positionInStream)); LOG.info(String.format( "Amazon Kinesis Managed Client prepared for %s on %s in %s (%s) using %s Max Records", config.getApplicationName(), config.getStreamName(), config.getRegionName(), config.getWorkerIdentifier(), config.getMaxRecords())); isConfigured = true; } catch (Exception e) { throw new InvalidConfigurationException(e); } } } public ManagedConsumer withKinesisEndpoint(String kinesisEndpoint) { this.kinesisEndpoint = kinesisEndpoint; return this; } public ManagedConsumer withToleratedWorkerFailures(int failuresToTolerate) { this.failuresToTolerate = failuresToTolerate; return this; } public ManagedConsumer withMaxRecords(int maxRecords) { this.maxRecords = maxRecords; return this; } public ManagedConsumer withRegionName(String regionName) { this.regionName = regionName; return this; } public ManagedConsumer withEnvironment(String environmentName) { this.environmentName = environmentName; return this; } public ManagedConsumer withCredentialsProvider(AWSCredentialsProvider credentialsProvider) { this.credentialsProvider = credentialsProvider; return this; } public ManagedConsumer withInitialPositionInStream(String positionInStream) { this.positionInStream = positionInStream; return this; } }