1212 */
1313package com .snowplowanalytics .snowplow .postgres .streaming
1414
15- import java .util .Base64
15+ import java .util .{Base64 , UUID }
16+ import java .net .InetAddress
1617import java .nio .charset .StandardCharsets
1718
1819import cats .implicits ._
1920
2021import cats .effect .{Blocker , ConcurrentEffect , ContextShift , Resource , Sync , Timer }
2122
2223import fs2 .Stream
23- import fs2 .aws .kinesis .{CommittableRecord , Kinesis , KinesisConsumerSettings }
24+ import fs2 .aws .kinesis .{CommittableRecord , Kinesis }
2425
2526import com .permutive .pubsub .consumer .grpc .{PubsubGoogleConsumer , PubsubGoogleConsumerConfig }
2627import io .circe .Json
@@ -41,6 +42,12 @@ import com.google.pubsub.v1.PubsubMessage
4142import com .permutive .pubsub .consumer .Model .{ProjectId , Subscription }
4243import com .permutive .pubsub .consumer .decoder .MessageDecoder
4344
45+ import software .amazon .awssdk .regions .Region
46+ import software .amazon .kinesis .common .ConfigsBuilder
47+ import software .amazon .kinesis .coordinator .Scheduler
48+ import software .amazon .kinesis .processor .ShardRecordProcessorFactory
49+ import software .amazon .kinesis .retrieval .polling .PollingConfig
50+ import software .amazon .kinesis .retrieval .fanout .FanOutConfig
4451import software .amazon .awssdk .services .cloudwatch .CloudWatchAsyncClient
4552import software .amazon .awssdk .services .dynamodb .DynamoDbAsyncClient
4653import software .amazon .awssdk .services .kinesis .KinesisAsyncClient
@@ -59,14 +66,13 @@ object source {
5966 */
6067 def getSource [F [_]: ConcurrentEffect : ContextShift : Timer ](blocker : Blocker , purpose : Purpose , config : Source ): Stream [F , Either [BadData , Data ]] =
6168 config match {
62- case LoaderConfig .Source .Kinesis (appName, streamName, region, position) =>
69+ case kConfig : LoaderConfig .Source .Kinesis =>
6370 for {
64- kinesisClient <- Stream .resource(makeKinesisClient[F ])
65- dynamoClient <- Stream .resource(makeDynamoDbClient[F ])
66- cloudWatchClient <- Stream .resource(makeCloudWatchClient[F ])
67- kinesis = Kinesis .create(kinesisClient, dynamoClient, cloudWatchClient, blocker)
68- settings = KinesisConsumerSettings .apply(streamName, appName, region, initialPositionInStream = position.unwrap)
69- record <- kinesis.readFromKinesisStream(settings)
71+ kinesisClient <- Stream .resource(makeKinesisClient[F ](kConfig.region))
72+ dynamoClient <- Stream .resource(makeDynamoDbClient[F ](kConfig.region))
73+ cloudWatchClient <- Stream .resource(makeCloudWatchClient[F ](kConfig.region))
74+ kinesis = Kinesis .create(blocker, scheduler(kinesisClient, dynamoClient, cloudWatchClient, kConfig, _))
75+ record <- kinesis.readFromKinesisStream(" THIS DOES NOTHING" , " THIS DOES NOTHING" )
7076 _ <- Stream .eval(record.checkpoint)
7177 } yield parseRecord(purpose, record)
7278 case LoaderConfig .Source .PubSub (projectId, subscriptionId) =>
@@ -135,12 +141,71 @@ object source {
135141 def pubsubOnFailedTerminate [F [_]: Sync ](error : Throwable ): F [Unit ] =
136142 Sync [F ].delay(logger.warn(s " Cannot terminate pubsub consumer properly \n ${error.getMessage}" ))
137143
138- def makeKinesisClient [F [_]: Sync ]: Resource [F , KinesisAsyncClient ] =
139- Resource .fromAutoCloseable(Sync [F ].delay(KinesisAsyncClient .create()))
144+ def scheduler [F [_]: Sync ](kinesisClient : KinesisAsyncClient ,
145+ dynamoDbClient : DynamoDbAsyncClient ,
146+ cloudWatchClient : CloudWatchAsyncClient ,
147+ config : LoaderConfig .Source .Kinesis ,
148+ recordProcessorFactory : ShardRecordProcessorFactory ): F [Scheduler ] =
149+ Sync [F ].delay(UUID .randomUUID()).map { uuid =>
150+ val hostname = InetAddress .getLocalHost().getCanonicalHostName()
151+
152+ val configsBuilder =
153+ new ConfigsBuilder (config.streamName,
154+ config.appName,
155+ kinesisClient,
156+ dynamoDbClient,
157+ cloudWatchClient,
158+ s " $hostname: $uuid" ,
159+ recordProcessorFactory)
160+
161+ val retrievalConfig =
162+ configsBuilder
163+ .retrievalConfig
164+ .initialPositionInStreamExtended(config.initialPosition.unwrap)
165+ .retrievalSpecificConfig {
166+ config.retrievalMode match {
167+ case LoaderConfig .Source .Kinesis .Retrieval .FanOut =>
168+ new FanOutConfig (kinesisClient)
169+ case LoaderConfig .Source .Kinesis .Retrieval .Polling (maxRecords) =>
170+ new PollingConfig (config.streamName, kinesisClient).maxRecords(maxRecords)
171+ }
172+ }
173+
174+ new Scheduler (
175+ configsBuilder.checkpointConfig,
176+ configsBuilder.coordinatorConfig,
177+ configsBuilder.leaseManagementConfig,
178+ configsBuilder.lifecycleConfig,
179+ configsBuilder.metricsConfig,
180+ configsBuilder.processorConfig,
181+ retrievalConfig
182+ )
183+ }
184+
185+ def makeKinesisClient [F [_]: Sync ](region : Region ): Resource [F , KinesisAsyncClient ] =
186+ Resource .fromAutoCloseable {
187+ Sync [F ].delay {
188+ KinesisAsyncClient .builder()
189+ .region(region)
190+ .build
191+ }
192+ }
140193
141- def makeDynamoDbClient [F [_]: Sync ]: Resource [F , DynamoDbAsyncClient ] =
142- Resource .fromAutoCloseable(Sync [F ].delay(DynamoDbAsyncClient .create()))
194+ def makeDynamoDbClient [F [_]: Sync ](region : Region ): Resource [F , DynamoDbAsyncClient ] =
195+ Resource .fromAutoCloseable {
196+ Sync [F ].delay {
197+ DynamoDbAsyncClient .builder()
198+ .region(region)
199+ .build
200+ }
201+ }
143202
144- def makeCloudWatchClient [F [_]: Sync ]: Resource [F , CloudWatchAsyncClient ] =
145- Resource .fromAutoCloseable(Sync [F ].delay(CloudWatchAsyncClient .create()))
203+ def makeCloudWatchClient [F [_]: Sync ](region : Region ): Resource [F , CloudWatchAsyncClient ] =
204+ Resource .fromAutoCloseable {
205+ Sync [F ].delay {
206+ CloudWatchAsyncClient .builder()
207+ .region(region)
208+ .build
209+ }
210+ }
146211}
0 commit comments