Skip to content
This repository was archived by the owner on May 21, 2020. It is now read-only.

Commit 1a9c22d

Browse files
Merge pull request #14 from DiceTechnology/kcl-2-upgrade
Kcl 2 upgrade
2 parents f1109ac + 505e3d4 commit 1a9c22d

File tree

11 files changed

+369
-264
lines changed

11 files changed

+369
-264
lines changed

project/Dependencies.scala

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import sbt._, Keys._
33
object Dependencies {
44

55
val AkkaVersion = sys.env.get("AKKA_SERIES") match {
6-
case Some("2.5") => "2.5.11"
6+
case Some("2.5") => "2.5.19"
77
case _ => "2.4.20"
88
}
99

10-
val AwsSdkVersion = "1.11.311"
10+
val AwsSdkVersion = "2.2.0"
1111

1212
val Common = Seq(
1313
libraryDependencies ++= Seq(
@@ -21,8 +21,10 @@ object Dependencies {
2121

2222
val Kinesis = Seq(
2323
libraryDependencies ++= Seq(
24-
"com.amazonaws" % "aws-java-sdk-kinesis" % AwsSdkVersion % Provided, // ApacheV2
25-
"com.amazonaws" % "amazon-kinesis-client" % "1.9.0" % Provided, // Amazon Software License
24+
"software.amazon.awssdk" % "kinesis" % AwsSdkVersion % Provided, // ApacheV2
25+
"software.amazon.awssdk" % "dynamodb" % AwsSdkVersion % Provided, // ApacheV2
26+
"software.amazon.awssdk" % "cloudwatch" % AwsSdkVersion % Provided, // ApacheV2
27+
"software.amazon.kinesis" % "amazon-kinesis-client" % "2.0.5" % Provided, // Amazon Software License
2628
"org.mockito" % "mockito-core" % "2.7.11" % Test // MIT
2729
)
2830
)

project/build.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.2.4
1+
sbt.version=1.2.6

src/main/scala/aserralle/akka/stream/kcl/CommittableRecord.scala

+14-20
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,43 @@
55
package aserralle.akka.stream.kcl
66

77
import akka.Done
8-
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorCheckpointer
9-
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.ShutdownReason
10-
import com.amazonaws.services.kinesis.clientlibrary.types.{
11-
ExtendedSequenceNumber,
12-
UserRecord
13-
}
14-
import com.amazonaws.services.kinesis.model.Record
8+
import software.amazon.kinesis.lifecycle.ShutdownReason
9+
import software.amazon.kinesis.processor.RecordProcessorCheckpointer
10+
import software.amazon.kinesis.retrieval.KinesisClientRecord
11+
import software.amazon.kinesis.retrieval.kpl.ExtendedSequenceNumber
1512

1613
import scala.concurrent.{ExecutionContext, Future}
1714

1815
class CommittableRecord(
1916
val shardId: String,
2017
val recordProcessorStartingSequenceNumber: ExtendedSequenceNumber,
2118
val millisBehindLatest: Long,
22-
val record: Record,
23-
recordProcessor: IRecordProcessor,
24-
checkpointer: IRecordProcessorCheckpointer
19+
val record: KinesisClientRecord,
20+
recordProcessor: ShardProcessor,
21+
checkpointer: RecordProcessorCheckpointer
2522
)(implicit executor: ExecutionContext) {
2623

27-
val sequenceNumber: String = record.getSequenceNumber
24+
val sequenceNumber: String = record.sequenceNumber()
25+
val subSequenceNumber: Long = record.subSequenceNumber()
2826

2927
def recordProcessorShutdownReason(): Option[ShutdownReason] =
3028
recordProcessor.shutdown
29+
3130
def canBeCheckpointed(): Boolean =
3231
recordProcessorShutdownReason().isEmpty
32+
3333
def tryToCheckpoint(): Future[Done] =
3434
Future {
35-
checkpointer.checkpoint(record)
35+
checkpointer.checkpoint(sequenceNumber, subSequenceNumber)
3636
Done
3737
}
38-
3938
}
4039

4140
object CommittableRecord {
4241

4342
// Only makes sense to compare Records belonging to the same shard
44-
// Records that have been batched by the KCL producer all have the
43+
// Records that have been batched by the KPL producer all have the
4544
// same sequence number but will differ by subsequence number
4645
implicit val orderBySequenceNumber: Ordering[CommittableRecord] =
47-
Ordering[(String, Long)].on(cr
48-
(cr.sequenceNumber, cr.record match {
49-
case ur: UserRecord ur.getSubSequenceNumber
50-
case _ 0
51-
}))
52-
46+
Ordering[(String, Long)].on(cr (cr.sequenceNumber, cr.subSequenceNumber))
5347
}

src/main/scala/aserralle/akka/stream/kcl/IRecordProcessor.scala

-62
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (C) 2018 Albert Serrallé
3+
*/
4+
5+
package aserralle.akka.stream.kcl
6+
7+
import software.amazon.kinesis.lifecycle.ShutdownReason
8+
import software.amazon.kinesis.lifecycle.events._
9+
import software.amazon.kinesis.processor.ShardRecordProcessor
10+
import software.amazon.kinesis.retrieval.kpl.ExtendedSequenceNumber
11+
12+
import scala.collection.JavaConverters._
13+
import scala.concurrent.ExecutionContext
14+
import scala.concurrent.duration.FiniteDuration
15+
16+
private[kcl] class ShardProcessor(
17+
callback: CommittableRecord => Unit,
18+
terminateStreamGracePeriod: FiniteDuration
19+
)(implicit executionContext: ExecutionContext)
20+
extends ShardRecordProcessor {
21+
22+
private var shardId: String = _
23+
private var extendedSequenceNumber: ExtendedSequenceNumber = _
24+
25+
var shutdown: Option[ShutdownReason] = None
26+
27+
override def initialize(initializationInput: InitializationInput): Unit = {
28+
shardId = initializationInput.shardId()
29+
extendedSequenceNumber = initializationInput.extendedSequenceNumber()
30+
}
31+
32+
override def processRecords(processRecordsInput: ProcessRecordsInput): Unit = {
33+
processRecordsInput.records().asScala.foreach { record =>
34+
callback(
35+
new CommittableRecord(
36+
shardId,
37+
extendedSequenceNumber,
38+
processRecordsInput.millisBehindLatest(),
39+
record,
40+
recordProcessor = this,
41+
processRecordsInput.checkpointer
42+
)
43+
)
44+
}
45+
}
46+
47+
override def leaseLost(leaseLostInput: LeaseLostInput): Unit = {}
48+
49+
override def shardEnded(shardEndedInput: ShardEndedInput): Unit = {
50+
// We need to checkpoint, but if we do it immediately any records still
51+
// in flight may get lost, so we wait for the grace period
52+
shutdown = Some(ShutdownReason.SHARD_END)
53+
Thread.sleep(terminateStreamGracePeriod.toMillis)
54+
shardEndedInput.checkpointer.checkpoint()
55+
}
56+
57+
override def shutdownRequested(shutdownInput: ShutdownRequestedInput): Unit = {
58+
// We don't checkpoint at this point as we assume the
59+
// standard mechanism will checkpoint when required
60+
shutdown = Some(ShutdownReason.REQUESTED)
61+
Thread.sleep(terminateStreamGracePeriod.toMillis)
62+
}
63+
64+
}

src/main/scala/aserralle/akka/stream/kcl/javadsl/KinesisWorkerSource.scala

+9-8
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,23 @@ import java.util.concurrent.Executor
99
import akka.NotUsed
1010
import aserralle.akka.stream.kcl.{CommittableRecord, scaladsl, _}
1111
import akka.stream.javadsl.{Flow, Sink, Source}
12-
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory
13-
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker
14-
import com.amazonaws.services.kinesis.model.Record
12+
import software.amazon.kinesis.coordinator.Scheduler
13+
import software.amazon.kinesis.processor.ShardRecordProcessorFactory
14+
import software.amazon.kinesis.retrieval.KinesisClientRecord
1515

1616
import scala.concurrent.ExecutionContext
1717

1818
object KinesisWorkerSource {
1919

2020
abstract class WorkerBuilder {
21-
def build(r: IRecordProcessorFactory): Worker
21+
def build(r: ShardRecordProcessorFactory): Scheduler
2222
}
2323

2424
def create(
2525
workerBuilder: WorkerBuilder,
2626
settings: KinesisWorkerSourceSettings,
2727
workerExecutor: Executor
28-
): Source[CommittableRecord, Worker] =
28+
): Source[CommittableRecord, Scheduler] =
2929
scaladsl.KinesisWorkerSource
3030
.apply(workerBuilder.build, settings)(
3131
ExecutionContext.fromExecutor(workerExecutor))
@@ -34,17 +34,18 @@ object KinesisWorkerSource {
3434
def create(
3535
workerBuilder: WorkerBuilder,
3636
workerExecutor: Executor
37-
): Source[CommittableRecord, Worker] =
37+
): Source[CommittableRecord, Scheduler] =
3838
create(workerBuilder,
3939
KinesisWorkerSourceSettings.defaultInstance,
4040
workerExecutor)
4141

4242
def checkpointRecordsFlow(
4343
settings: KinesisWorkerCheckpointSettings
44-
): Flow[CommittableRecord, Record, NotUsed] =
44+
): Flow[CommittableRecord, KinesisClientRecord, NotUsed] =
4545
scaladsl.KinesisWorkerSource.checkpointRecordsFlow(settings).asJava
4646

47-
def checkpointRecordsFlow(): Flow[CommittableRecord, Record, NotUsed] =
47+
def checkpointRecordsFlow()
48+
: Flow[CommittableRecord, KinesisClientRecord, NotUsed] =
4849
checkpointRecordsFlow(KinesisWorkerCheckpointSettings.defaultInstance)
4950

5051
def checkpointRecordsSink(

src/main/scala/aserralle/akka/stream/kcl/scaladsl/KinesisWorkerSource.scala

+17-13
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ import aserralle.akka.stream.kcl.Errors.{
1616
}
1717
import aserralle.akka.stream.kcl.{
1818
CommittableRecord,
19-
IRecordProcessor,
2019
KinesisWorkerCheckpointSettings,
21-
KinesisWorkerSourceSettings
20+
KinesisWorkerSourceSettings,
21+
ShardProcessor
2222
}
23-
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory
24-
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker
25-
import com.amazonaws.services.kinesis.model.Record
23+
import software.amazon.kinesis.coordinator.Scheduler
24+
import software.amazon.kinesis.exceptions.ShutdownException
25+
import software.amazon.kinesis.processor.{
26+
ShardRecordProcessor,
27+
ShardRecordProcessorFactory
28+
}
29+
import software.amazon.kinesis.retrieval.KinesisClientRecord
2630

2731
import scala.collection.immutable
2832
import scala.concurrent.{Await, ExecutionContext, Future}
@@ -32,11 +36,11 @@ import scala.util.{Failure, Success}
3236
object KinesisWorkerSource {
3337

3438
def apply(
35-
workerBuilder: IRecordProcessorFactory => Worker,
39+
workerBuilder: ShardRecordProcessorFactory => Scheduler,
3640
settings: KinesisWorkerSourceSettings =
3741
KinesisWorkerSourceSettings.defaultInstance
3842
)(implicit workerExecutor: ExecutionContext)
39-
: Source[CommittableRecord, Worker] =
43+
: Source[CommittableRecord, Scheduler] =
4044
Source
4145
.queue[CommittableRecord](settings.bufferSize,
4246
OverflowStrategy.backpressure)
@@ -45,9 +49,9 @@ object KinesisWorkerSource {
4549
case (queue, watch) =>
4650
val semaphore = new Semaphore(1, true)
4751
val worker = workerBuilder(
48-
new IRecordProcessorFactory {
49-
override def createProcessor(): IRecordProcessor =
50-
new IRecordProcessor(
52+
new ShardRecordProcessorFactory {
53+
override def shardRecordProcessor(): ShardRecordProcessor =
54+
new ShardProcessor(
5155
record => {
5256
semaphore.acquire(1)
5357
(Exception.nonFatalCatch either Await.result(
@@ -73,7 +77,7 @@ object KinesisWorkerSource {
7377
def checkpointRecordsFlow(
7478
settings: KinesisWorkerCheckpointSettings =
7579
KinesisWorkerCheckpointSettings.defaultInstance
76-
): Flow[CommittableRecord, Record, NotUsed] =
80+
): Flow[CommittableRecord, KinesisClientRecord, NotUsed] =
7781
Flow[CommittableRecord]
7882
.groupBy(MAX_KINESIS_SHARDS, _.shardId)
7983
.groupedWithin(settings.maxBatchSize, settings.maxBatchWait)
@@ -83,7 +87,7 @@ object KinesisWorkerSource {
8387
val `{` =
8488
b.add(scaladsl.Broadcast[immutable.Seq[CommittableRecord]](2))
8589
val `}` = b.add(Zip[Done, immutable.Seq[CommittableRecord]])
86-
val `=` = b.add(Flow[Record])
90+
val `=` = b.add(Flow[KinesisClientRecord])
8791

8892
`{`.out(0)
8993
.map(_.max)
@@ -98,7 +102,7 @@ object KinesisWorkerSource {
98102
})
99103
.mergeSubstreams
100104
.withAttributes(ActorAttributes.supervisionStrategy {
101-
case _: com.amazonaws.services.kinesis.clientlibrary.exceptions.ShutdownException =>
105+
case _: ShutdownException =>
102106
Resume
103107
case _ => Stop
104108
})

0 commit comments

Comments
 (0)