@@ -570,6 +570,10 @@ module Consumer =
570570 let! state = Group.stateInternal c.groupMember
571571 return consumerStateFromGroupMemberState state.state }
572572
573+ /// Returns the stream of consumer states as of the invocation, including the current state.
574+ let states ( c : Consumer ) : AsyncSeq < ConsumerState > =
575+ Group.states c.groupMember |> AsyncSeq.map ( consumerStateFromGroupMemberState)
576+
573577 let private combineFetchResponses
574578 ( r1 :( ConsumerMessageSet [] * ( Partition * HighwaterMarkOffset )[]) option )
575579 ( r2 :( ConsumerMessageSet [] * ( Partition * HighwaterMarkOffset )[]) option ) =
@@ -862,32 +866,32 @@ module Consumer =
862866 ( c : Consumer )
863867 ( commitInterval : TimeSpan )
864868 ( handler : ConsumerState -> ConsumerMessageSet -> Async < unit >) : Async < unit > = async {
865-
866869 let assignedPartitions = state c |> Async.map ( fun s -> s.assignments)
867-
868- use commitQueue = Offsets.createPeriodicCommitQueue ( commitInterval, assignedPartitions, commitOffsets c)
869-
870- let! currentOffsets = async {
871- let! assignedPartitions = assignedPartitions
872- let! currentOffsets = fetchOffsets c.conn c.config.groupId [| c.config.topic, assignedPartitions |]
873- return
874- currentOffsets
875- |> Seq.choose ( fun ( t , os ) -> if t = c.config.topic then Some os else None)
876- |> Seq.concat
877- |> Seq.where ( fun ( _ , o ) -> o <> - 1 L)
878- |> Seq.toArray }
879-
880- // commit current offets so that they're in-memory, and will be committed periodically
881- // even if no messages are consumed
882- Offsets.enqueuePeriodicCommit commitQueue currentOffsets
883-
870+ use commitQueue = Offsets.createPeriodicCommitQueue ( commitInterval, assignedPartitions, commitOffsets c)
871+ // commit current offets on group rebalance, including first join,
872+ // so that they're committed periodically even if no messages are consumed
873+ let commitCurrentOffsetsOnGroupJoinProc =
874+ states c
875+ |> AsyncSeq.iterAsync ( fun s -> async {
876+ let! currentOffsets = async {
877+ let! currentOffsets = fetchOffsets c.conn c.config.groupId [| c.config.topic, s.assignments |]
878+ return
879+ currentOffsets
880+ |> Seq.choose ( fun ( t , os ) -> if t = c.config.topic then Some os else None)
881+ |> Seq.concat
882+ |> Seq.where ( fun ( _ , o ) -> o <> - 1 L)
883+ |> Seq.toArray }
884+ Offsets.enqueuePeriodicCommit commitQueue currentOffsets })
884885 let handler s ms = async {
885886 do ! handler s ms
886- Offsets.enqueuePeriodicCommit commitQueue ( ConsumerMessageSet.commitPartitionOffsets ms) }
887-
888- do ! consume c handler
889-
890- do ! Offsets.flushPeriodicCommit commitQueue }
887+ Offsets.enqueuePeriodicCommit commitQueue ( ConsumerMessageSet.commitPartitionOffsets ms) }
888+ do !
889+ Async.parallel2
890+ ( async {
891+ do ! consume c handler
892+ do ! Offsets.flushPeriodicCommit commitQueue },
893+ commitCurrentOffsetsOnGroupJoinProc)
894+ |> Async.Ignore }
891895
892896 /// Closes the consumer and leaves the consumer group.
893897 /// This causes all underlying streams to complete.
0 commit comments