package com.sumologic.kinesis; import org.apache.log4j.Logger; import com.sumologic.kinesis.KinesisConnectorRecordProcessorFactory; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.KinesisClientLibConfiguration; import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker; import com.amazonaws.services.kinesis.connectors.KinesisConnectorConfiguration; import com.amazonaws.services.kinesis.metrics.impl.NullMetricsFactory; import com.amazonaws.services.kinesis.metrics.interfaces.IMetricsFactory; public abstract class KinesisConnectorExecutorBase<T, U> implements Runnable { private static final Logger LOG = Logger.getLogger(KinesisConnectorExecutorBase.class.getName()); // Amazon Kinesis Client Library worker to process records protected Worker worker; /** * Initialize the Amazon Kinesis Client Library configuration and worker * * @param kinesisConnectorConfiguration Amazon Kinesis connector configuration */ protected void initialize(KinesisConnectorConfiguration kinesisConnectorConfiguration) { initialize(kinesisConnectorConfiguration, new NullMetricsFactory()); } /** * Initialize the Amazon Kinesis Client Library configuration and worker with metrics factory * * @param kinesisConnectorConfiguration Amazon Kinesis connector configuration * @param metricFactory would be used to emit metrics in Amazon Kinesis Client Library */ protected void initialize(KinesisConnectorConfiguration kinesisConnectorConfiguration, IMetricsFactory metricFactory) { KinesisClientLibConfiguration kinesisClientLibConfiguration = new KinesisClientLibConfiguration(kinesisConnectorConfiguration.APP_NAME, kinesisConnectorConfiguration.KINESIS_INPUT_STREAM, kinesisConnectorConfiguration.AWS_CREDENTIALS_PROVIDER, kinesisConnectorConfiguration.WORKER_ID).withKinesisEndpoint(kinesisConnectorConfiguration.KINESIS_ENDPOINT) .withFailoverTimeMillis(kinesisConnectorConfiguration.FAILOVER_TIME) .withMaxRecords(kinesisConnectorConfiguration.MAX_RECORDS) .withInitialPositionInStream(kinesisConnectorConfiguration.INITIAL_POSITION_IN_STREAM) .withIdleTimeBetweenReadsInMillis(kinesisConnectorConfiguration.IDLE_TIME_BETWEEN_READS) .withCallProcessRecordsEvenForEmptyRecordList(KinesisConnectorConfiguration.DEFAULT_CALL_PROCESS_RECORDS_EVEN_FOR_EMPTY_LIST) .withCleanupLeasesUponShardCompletion(kinesisConnectorConfiguration.CLEANUP_TERMINATED_SHARDS_BEFORE_EXPIRY) .withParentShardPollIntervalMillis(kinesisConnectorConfiguration.PARENT_SHARD_POLL_INTERVAL) .withShardSyncIntervalMillis(kinesisConnectorConfiguration.SHARD_SYNC_INTERVAL) .withTaskBackoffTimeMillis(kinesisConnectorConfiguration.BACKOFF_INTERVAL) .withMetricsBufferTimeMillis(kinesisConnectorConfiguration.CLOUDWATCH_BUFFER_TIME) .withMetricsMaxQueueSize(kinesisConnectorConfiguration.CLOUDWATCH_MAX_QUEUE_SIZE) .withUserAgent(kinesisConnectorConfiguration.APP_NAME + "," + kinesisConnectorConfiguration.CONNECTOR_DESTINATION + "," + KinesisConnectorConfiguration.KINESIS_CONNECTOR_USER_AGENT) .withRegionName(kinesisConnectorConfiguration.REGION_NAME); if (!kinesisConnectorConfiguration.CALL_PROCESS_RECORDS_EVEN_FOR_EMPTY_LIST) { LOG.warn("The false value of callProcessRecordsEvenForEmptyList will be ignored. It must be set to true for the bufferTimeMillisecondsLimit to work correctly."); } if (kinesisConnectorConfiguration.IDLE_TIME_BETWEEN_READS > kinesisConnectorConfiguration.BUFFER_MILLISECONDS_LIMIT) { LOG.warn("idleTimeBetweenReads is greater than bufferTimeMillisecondsLimit. For best results, ensure that bufferTimeMillisecondsLimit is more than or equal to idleTimeBetweenReads "); } // If a metrics factory was specified, use it. if (metricFactory != null) { worker = new Worker(getKinesisConnectorRecordProcessorFactory(), kinesisClientLibConfiguration, metricFactory); } else { worker = new Worker(getKinesisConnectorRecordProcessorFactory(), kinesisClientLibConfiguration); } LOG.info(getClass().getSimpleName() + " worker created"); } @Override public void run() { if (worker != null) { // Start Amazon Kinesis Client Library worker to process records LOG.info("Starting worker in " + getClass().getSimpleName()); try { worker.run(); } catch (Throwable t) { LOG.error(t); throw t; } finally { LOG.error("Worker " + getClass().getSimpleName() + " is not running."); } } else { throw new RuntimeException("Initialize must be called before run."); } } /** * This method returns a {@link KinesisConnectorRecordProcessorFactory} that contains the * appropriate {@link IKinesisConnectorPipeline} for the Amazon Kinesis Enabled Application * * @return a {@link KinesisConnectorRecordProcessorFactory} that contains the appropriate * {@link IKinesisConnectorPipeline} for the Amazon Kinesis Enabled Application */ public abstract KinesisConnectorRecordProcessorFactory<T, U> getKinesisConnectorRecordProcessorFactory(); }