-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider moving commit method from CommitableOffset (and some others) to KafkaConsumer #462
Comments
We could consider adding the new methods to |
Another thing we could consider is for a |
@bplommer great idea! I think with this approach we could maintain source compatibility with the current version. |
@LMnet do you think this is something you'd like to pick up? |
@bplommer yes, I will try to find some time for that. If I will not submit a pull request until March 14 you could interpret that I did not find the time. |
I started to work and faced an issue with the
Moving further I thought about the reasons, why Moreover, we could try to use path-dependent types for that. With this, we will have a compile-time guarantee that offsets from different consumers are not mixed in the same batch. But I'm concerned about this change — how it will affect library users? |
I played a bit with path-dependent types and it will work, but I think it would be not practical. I did something like this (simplified): trait KafkaConsumer[F[_]] { outer =>
// some methods here
private[kafka] def commitInternal(offsets: Map[TopicPartition, OffsetAndMetadata]): F[Unit]
case class CommittableOffset(topicPartition: TopicPartition, offsetAndMetadata: OffsetAndMetadata)
object CommittableOffset {
implicit class CommittableOffsetOps(val self: CommittableOffset) {
def offsets: Map[TopicPartition, OffsetAndMetadata] = Map(self.topicPartition -> self.offsetAndMetadata)
def commit: F[Unit] = outer.commitInternal(offsets)
}
implicit val eq: Eq[CommittableOffset] = ???
}
case class CommittableOffsetBatch(offsets: Map[TopicPartition, OffsetAndMetadata])
object CommittableOffsetBatch = {
implicit class CommittableOffsetBatchOps(val self: CommittableOffsetBatch) {
def commit: F[Unit] = outer.commitInternal(self.offsets)
}
implicit val eq: Eq[CommittableOffsetBatch] = ???
}
} This approach will give complete type safety. There is no way to messed up with the But there is also def foo(record: CommittableConsumerRecord[F, A, B]): CommittableConsumerRecord[F, A, B] = ??? // doing some stuff with record Users will have to do something like this: def foo(record: consumer.CommittableConsumerRecord[F, A, B]): consumer.CommittableConsumerRecord[F, A, B] = ??? This variant will widen a type and we will loose type-safety: def foo(record: KafkaConsumer#CommittableConsumerRecord[F, A, B]): KafkaConsumer#CommittableConsumerRecord[F, A, B] = ??? So, it looks like path-dependent types are not an option here. I think the best approach will be to refactor
Also, there is a related issue about the safety of |
I agree this option is preferable, if possible. |
There is also another option: allow def offsets: Map[TopicPartition, OffsetAndMetadata]
def offsets: Map[KafkaCommit[F], Map[TopicPartition, OffsetAndMetadata]] It will automatically save us from the problems like #347. And also, |
Could we improve the ergonomics by having a wrapper for the path dependent type? So we have something like sealed trait WrappedCommittableConsumerRecord[F[_], K, V] {
val consumer: KafkaConsumer[F, K, V]
val record: consumer.CommittableConsumerRecord
} and then client code would be def foo(record: WrappedCommittableConsumerRecord[F, A, B]): record.consumer.CommittableConsumerRecord = ??? It's very likely that that there's something I'm missing, but could this work? |
Well, it will work, yes. But it will be:
The more I think about this issue the more I leaning towards my last solution (when |
That sounds reasonable to me. |
I'm trying to implement a version where Overall all looks fine. sealed abstract class CommittableOffset[F[_]] {
def topicPartition: TopicPartition
def offsetAndMetadata: OffsetAndMetadata
def committer: KafkaCommit[F]
} And sealed abstract class CommittableOffsetBatch[F[_]] {
def offsets: Map[KafkaCommit[F], Map[TopicPartition, OffsetAndMetadata]]
} But I have some difficulties with the
@bplommer @vlovgr wdyt? Maybe you could offer some other options to solve this issue? |
During the discussion of #409 I suggested that
commit
method from theCommitableOffset
could be moved to theKafkaConsumer
.CommittableOffset
feels like pure data, but it containsdef commit: F[Unit]
, which is not data, but a behavior. Maybe it would be better ifCommittableOffset
will not have thecommit
method? Maybe it would be more natural to have it onKafkaConsumer
(likedef commit(committableOffset: CommitableOffset): F[Unit]
)?The presence of the
commit
method in theCommittableOffset
adds some difficulties for creating instances likeEq
forCommittableOffset
.All
Committable...
types affected by this problem too.As a complement to the
KafkaConsumer#commit
method, we could implementcommit
on theCommittableOffset
as an extension method. It will requireKafkaConsumer
as an input argument, but overall I think it will help to maintain the current API as much as possible.The text was updated successfully, but these errors were encountered: