-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Track latest completed commit offset per partition (#1097)
By tracking these offsets we can skip awaiting already completed commits from the rebalance listener in #830. To prevent unbounded memory usage, after a rebalance we remove the committed offset for partitions that are no longer assigned to this consumer. Note that a commit might complete just after a partition was revoked. This is not a big issue; the offset will still be removed in the next rebalance. When the `rebalanceSafeCommits` feature is available and enabled (see #830) commits will complete in the rebalance listener and this cannot happen anymore. The offsets map is wrapped in a case class for 2 reasons: * It provides a very nice place to put the updating methods. * Having updating methods makes the code that uses `CommitOffsets` very concise.
- Loading branch information
1 parent
21361c1
commit 5fb8b5e
Showing
2 changed files
with
110 additions
and
9 deletions.
There are no files selected for viewing
65 changes: 65 additions & 0 deletions
65
zio-kafka-test/src/test/scala/zio/kafka/consumer/internal/RunloopCommitOffsetsSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package zio.kafka.consumer.internal | ||
|
||
import org.apache.kafka.common.TopicPartition | ||
import zio._ | ||
import org.apache.kafka.clients.consumer.OffsetAndMetadata | ||
import zio.test._ | ||
|
||
object RunloopCommitOffsetsSpec extends ZIOSpecDefault { | ||
|
||
private val tp10 = new TopicPartition("t1", 0) | ||
private val tp11 = new TopicPartition("t1", 1) | ||
private val tp20 = new TopicPartition("t2", 0) | ||
private val tp21 = new TopicPartition("t2", 1) | ||
private val tp22 = new TopicPartition("t2", 2) | ||
|
||
override def spec: Spec[TestEnvironment with Scope, Any] = | ||
suite("Runloop.CommitOffsets spec")( | ||
test("addCommits adds to empty CommitOffsets") { | ||
val s1 = Runloop.CommitOffsets(Map.empty) | ||
val s2 = s1.addCommits(Chunk(makeCommit(Map(tp10 -> 10)))) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L)) | ||
}, | ||
test("addCommits updates offset when it is higher") { | ||
val s1 = Runloop.CommitOffsets(Map(tp10 -> 5L)) | ||
val s2 = s1.addCommits(Chunk(makeCommit(Map(tp10 -> 10)))) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L)) | ||
}, | ||
test("addCommits ignores an offset when it is lower") { | ||
val s1 = Runloop.CommitOffsets(Map(tp10 -> 10L)) | ||
val s2 = s1.addCommits(Chunk(makeCommit(Map(tp10 -> 5)))) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L)) | ||
}, | ||
test("addCommits keeps unrelated partitions") { | ||
val s1 = Runloop.CommitOffsets(Map(tp10 -> 10L)) | ||
val s2 = s1.addCommits(Chunk(makeCommit(Map(tp11 -> 11)))) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L, tp11 -> 11L)) | ||
}, | ||
test("addCommits does it all at once") { | ||
val s1 = Runloop.CommitOffsets(Map(tp10 -> 10L, tp20 -> 205L, tp21 -> 210L, tp22 -> 220L)) | ||
val s2 = s1.addCommits(Chunk(makeCommit(Map(tp11 -> 11, tp20 -> 206L, tp21 -> 209L, tp22 -> 220L)))) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L, tp11 -> 11L, tp20 -> 206L, tp21 -> 210L, tp22 -> 220L)) | ||
}, | ||
test("addCommits adds multiple commits") { | ||
val s1 = Runloop.CommitOffsets(Map(tp10 -> 10L, tp20 -> 200L, tp21 -> 210L, tp22 -> 220L)) | ||
val s2 = s1.addCommits( | ||
Chunk( | ||
makeCommit(Map(tp11 -> 11, tp20 -> 199L, tp21 -> 211L, tp22 -> 219L)), | ||
makeCommit(Map(tp20 -> 198L, tp21 -> 209L, tp22 -> 221L)) | ||
) | ||
) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L, tp11 -> 11L, tp20 -> 200L, tp21 -> 211L, tp22 -> 221L)) | ||
}, | ||
test("keepPartitions removes some partitions") { | ||
val s1 = Runloop.CommitOffsets(Map(tp10 -> 10L, tp20 -> 20L)) | ||
val s2 = s1.keepPartitions(Set(tp10)) | ||
assertTrue(s2.offsets == Map(tp10 -> 10L)) | ||
} | ||
) | ||
|
||
private def makeCommit(offsets: Map[TopicPartition, Long]): RunloopCommand.Commit = { | ||
val o = offsets.map { case (tp, offset) => tp -> new OffsetAndMetadata(offset) } | ||
val p = Unsafe.unsafe(implicit unsafe => Promise.unsafe.make[Throwable, Unit](FiberId.None)) | ||
RunloopCommand.Commit(o, p) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters