Пример #1
0
 /// <summary>
 /// Handles an acknowlegement in the case there is no associated ProduceResponse.
 /// Messages are reenqueued if they were never sent in the first place or if we
 /// are in Retry mode. They're discarded otherwise, in which case the MessageDiscarded
 /// event is raised.
 /// </summary>
 /// <param name="acknowledgement"></param>
 private void HandleProduceAcknowledgementNone(ProduceAcknowledgement acknowledgement)
 {
     foreach (var message in acknowledgement.OriginalBatch.SelectMany(gt => gt.SelectMany(gp => gp)))
     {
         if (_configuration.ErrorStrategy == ErrorStrategy.Retry ||
             acknowledgement.ReceiveDate == default(DateTime))
         {
             // Repost
             ReEnqueue(message);
         }
         else
         {
             // Discard
             OnMessageDiscarded(message);
         }
     }
 }
Пример #2
0
        /// <summary>
        /// Handle an acknowledgement with a ProduceResponse. Essentially search for errors and discard/retry
        /// accordingly. The logic is rather painful and boring. We try to be as efficient as possible
        /// in the standard case (i.e. no error).
        /// </summary>
        /// <param name="acknowledgement"></param>
        /// <returns></returns>
        private async Task HandleProduceAcknowledgement(ProduceAcknowledgement acknowledgement)
        {
            // The whole point of scanning the response is to search for errors
            var originalBatch   = acknowledgement.OriginalBatch;
            var produceResponse = acknowledgement.ProduceResponse.ProducePartitionResponse;
            var throttled       = acknowledgement.ProduceResponse.ThrottleTime;

            if (throttled > 0)
            {
                Throttled(throttled);
            }

            // Fill partitions in error caches
            _tmpPartitionsInError.Clear();
            _tmpPartitionsInRecoverableError.Clear();
            foreach (var tr in produceResponse.TopicsResponse)
            {
                bool errors = false;
                foreach (var p in tr.PartitionsData.Where(p => !IsPartitionOkForClients(p.ErrorCode)))
                {
                    if (!errors)
                    {
                        errors = true;
                        _tmpPartitionsInError[tr.TopicName]            = new HashSet <int>();
                        _tmpPartitionsInRecoverableError[tr.TopicName] = new HashSet <int>();
                    }

                    if (Error.IsPartitionErrorRecoverableForProducer(p.ErrorCode))
                    {
                        _cluster.Logger.LogWarning(
                            string.Format("Recoverable error detected: [topic: {0} - partition: {1} - error: {2}]",
                                          tr.TopicName, p.Partition, p.ErrorCode));
                        _tmpPartitionsInRecoverableError[tr.TopicName].Add(p.Partition);
                        if (p.ErrorCode != ErrorCode.InvalidMessageSize && p.ErrorCode != ErrorCode.InvalidMessage)
                        {
                            _cluster.Logger.LogWarning(
                                string.Format("Will ignore [topic: {0} / partition: {1}] for a time", tr.TopicName,
                                              p.Partition));
                            BlacklistPartition(tr.TopicName, p.Partition);

                            if (p.ErrorCode == ErrorCode.RequestTimedOut)
                            {
                                BrokerTimeoutError(tr.TopicName);
                            }
                        }
                    }
                    else
                    {
                        _cluster.Logger.LogError(
                            string.Format("Irrecoverable error detected: [topic: {0} - partition: {1} - error: {2}]",
                                          tr.TopicName, p.Partition, p.ErrorCode));
                        _tmpPartitionsInError[tr.TopicName].Add(p.Partition);
                    }
                }
            }

            // In case of recoverable errors, refresh metadata if they are too old
            if (_tmpPartitionsInRecoverableError.Count > 0 && acknowledgement.ReceiveDate > _routingTable.LastRefreshed)
            {
                await EnsureHasRoutingTable();
            }

            // Scan messages for errors and release memory if needed.
            // Messages associated to recoverable errors are reenqueued for rerouting,
            // messages with irrecoverable errors are discarded and messages with
            // no error are marked sent.
            foreach (var grouping in originalBatch)
            {
                int           sent = 0;
                HashSet <int> errPartitions;
                if (!_tmpPartitionsInError.TryGetValue(grouping.Key, out errPartitions))
                {
                    errPartitions = NullHash;
                }
                HashSet <int> recPartitions;
                if (!_tmpPartitionsInRecoverableError.TryGetValue(grouping.Key, out recPartitions))
                {
                    recPartitions = NullHash;
                }

                foreach (var pm in grouping.SelectMany(g => g))
                {
                    if (recPartitions.Contains(pm.Partition))
                    {
                        ReEnqueue(pm);
                    }
                    else
                    {
                        if (errPartitions.Contains(pm.Partition))
                        {
                            _cluster.Logger.LogError(
                                string.Format(
                                    "[Producer] Irrecoverable error, discarding message for [topic: {0} / partition: {1}]",
                                    pm.Topic, pm.Partition));
                            OnMessageDiscarded(pm);
                        }
                        else
                        {
                            ++sent;
                            ClearMessage(pm.Message);
                        }
                    }
                }
                if (sent > 0)
                {
                    MessagesAcknowledged(grouping.Key, sent);
                }
            }
        }
Пример #3
0
 /// <summary>
 /// Accept an acknowledgement request. Post a ProduceEvent message
 /// to the inner actor.
 /// </summary>
 /// <param name="acknowledgement"></param>
 public void Acknowledge(ProduceAcknowledgement acknowledgement)
 {
     _produceResponses.Enqueue(acknowledgement);
     _messages.Post(RouterMessageType.ProduceEvent);
 }