コード例 #1
0
        /// <summary>
        /// Handle a partition response for a given topic: filter out of range messages
        /// (can happen when receiving compressed messages), update the partitions states for the
        /// topic, emit all received messages on the dispatcher, and issue a new Fetch request if needed.
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="partitionResponse"></param>
        /// <returns></returns>
        private async Task HandleFetchPartitionResponse(string topic, FetchPartitionResponse partitionResponse)
        {
            var state = _partitionsStates[topic][partitionResponse.Partition];

            if (!state.Active)
            {
                return;
            }

            // Filter messages under required offset, this may happen when receiving
            // compressed messages. The Kafka protocol specifies it's up to the client
            // to filter out those messages. We also filter messages with offset greater
            // than the required stop offset if set.
            foreach (
                var message in
                partitionResponse.Messages.Where(
                    message =>
                    message.Offset >= state.NextOffsetExpected &&
                    (state.StopAt < 0 || message.Offset <= state.StopAt)))
            {
                state.LastOffsetSeen = message.Offset;
                MessageReceived(new RawKafkaRecord
                {
                    Topic     = topic,
                    Key       = message.Message.Key,
                    Value     = message.Message.Value,
                    Offset    = message.Offset,
                    Partition = partitionResponse.Partition
                });
            }

            ResponseMessageListPool.Release(partitionResponse.Messages);

            // Stop if we have seen the last required offset
            // TODO: what if we never see it?
            if (state.StopAt != Offsets.Never && state.LastOffsetSeen >= state.StopAt)
            {
                state.Active = false;
                return;
            }

            // Loop fetch request
            if (state.LastOffsetSeen >= Offsets.Some)
            {
                state.NextOffsetExpected = state.LastOffsetSeen + 1;
            }
            await Fetch(topic, partitionResponse.Partition, state.NextOffsetExpected);
        }
コード例 #2
0
        /// <summary>
        /// Handle a partition response for a given topic: filter out of range messages
        /// (can happen when receiving compressed messages), update the partitions states for the
        /// topic, emit all received messages on the dispatcher, and issue a new Fetch request if needed.
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="partitionResponse"></param>
        /// <returns></returns>
        private async Task HandleFetchPartitionResponse(string topic, FetchPartitionResponse partitionResponse)
        {
            var state = _partitionsStates[topic][partitionResponse.Partition];

            if (partitionResponse.ErrorCode == ErrorCode.OffsetOutOfRange)
            {
                _cluster.Logger.LogWarning(
                    string.Format(
                        "Offset {3} out of range for topic {0} / partition {1}, will read from {2} offset instead.", topic,
                        partitionResponse.Partition,
                        _configuration.OffsetOutOfRangeStrategy == Public.Offset.Earliest ? "earliest" : "latest", state.NextOffset));
                state.Active = false;
                StartConsume(topic, partitionResponse.Partition, (long)_configuration.OffsetOutOfRangeStrategy);
            }
            else
            {
                if (CheckActivity(state, topic, partitionResponse.Partition))
                {
                    // Filter messages under required offset, this may happen when receiving
                    // compressed messages. The Kafka protocol specifies it's up to the client
                    // to filter out those messages. We also filter messages with offset greater
                    // than the required stop offset if set.
                    long firstRequired = state.NextOffset;
                    foreach (var message in
                             partitionResponse.Messages.Where(
                                 message =>
                                 message.Offset >= firstRequired && (state.StopAt < 0 || message.Offset <= state.StopAt))
                             )
                    {
                        MessageReceived(new RawKafkaRecord
                        {
                            Topic     = topic,
                            Key       = message.Message.Key,
                            Value     = message.Message.Value,
                            Offset    = message.Offset,
                            Lag       = partitionResponse.HighWatermarkOffset - message.Offset,
                            Partition = partitionResponse.Partition,
                            Timestamp = Timestamp.FromUnixTimestamp(message.Message.TimeStamp)
                        });
                        state.NextOffset = message.Offset + 1;

                        await CheckHeartbeat();
                        await CheckCommit(null);

                        // Recheck status (may have changed if heartbeat triggered rebalance)
                        // TODO: is it really useful to check for heartbeat/commit after each message ?
                        // It's merely a defense versus bad message handler, maybe we don't care and
                        // just better check only at the beginning of partition processing.
                        if (!CheckActivity(state, topic, partitionResponse.Partition))
                        {
                            break;
                        }
                    }
                }

                ResponseMessageListPool.Release(partitionResponse.Messages);

                await CheckCommit(null);

                // Stop if we have seen the last required offset
                // TODO: what if we never see it?
                if (!state.Active || (state.StopAt != Offsets.Never && state.NextOffset > state.StopAt))
                {
                    state.Active = false;
                    return;
                }

                // Loop fetch request
                await Fetch(topic, partitionResponse.Partition, state.NextOffset);
            }
        }