Example #1
0
        internal async Task<FetchResponse> Fetch(FetchRequest req, Connection conn)
        {
            _log.Debug("Sending FetchRequest to broker {1}. Request: {0}", req, conn);
            if (_etw.IsEnabled())
                _etw.ProtocolFetchRequest(req.ToString());
            
            // Detect disconnected server. Wait no less than 5sec. 
            // If wait time exceed wait time + 3sec, consider it a timeout too
            //var timeout = Math.Max(5000, req.MaxWaitTime + 3000);
            //var cancel = new CancellationTokenSource(timeout);

            var tcp = await conn.GetClientAsync();
            var response = await conn.Correlation.SendAndCorrelateAsync(
                id => Serializer.Serialize(req, id),
                Serializer.DeserializeFetchResponse,
                tcp, /*cancel.Token*/ CancellationToken.None);

            if (_etw.IsEnabled())
                _etw.ProtocolFetchResponse(response.ToString());

            return response;
        }
Example #2
0
        private IObservable<FetchResponse> FetchLoop()
        {
            return Observable.Create<FetchResponse>(async observer =>
            {
                while (!_cancel.IsCancellationRequested)
                {
                    var fetchRequest = new FetchRequest
                    {
                        MaxWaitTime = _consumerConfig.MaxWaitTimeMs,
                        MinBytes = _consumerConfig.MinBytesPerFetch,
                        Topics = _topicPartitions.
                            Where(tp => {
                                var enabled = tp.FlowControlEnabled;
                                if(!enabled)
                                    _log.Debug("#{0} Ignoring partition because flow controll is off {1}", _id, tp);
                                return enabled;
                            }).
                            GroupBy(tp=>tp.Topic).
                            Select(t => new FetchRequest.TopicData { 
                                Topic = t.Key,
                                Partitions = t.
                                    Select(p => new FetchRequest.PartitionData
                                    {
                                        Partition = p.PartitionId,
                                        FetchOffset = p.CurrentOffset,
                                        MaxBytes = _consumerConfig.MaxBytesPerFetch
                                    }).ToArray()
                            }).ToArray()
                    };

                    if (fetchRequest.Topics.Length == 0)
                    {
                        _log.Debug("#{0} No partitions subscribed to fetcher. Waiting for _wakeupSignal signal", _id);
                        EtwTrace.Log.FetcherSleep(_id);
                        await _wakeupSignal.FirstAsync();
                        EtwTrace.Log.FetcherWakeup(_id);
                        
                        if(_cancel.IsCancellationRequested)
                        {
                            _log.Debug("#{0}Cancel detected. Quitting FetchLoop", _id);
                            break;
                        }
                        
                        _log.Debug("#{0} Received _wakeupSignal. Have {1} partitions subscribed", _id, _topicPartitions.Count);
                        continue;
                    }

                    // issue fetch 
                    FetchResponse fetch;
                    try
                    {
                        EtwTrace.Log.FetcherFetchRequest(_id, fetchRequest.Topics.Length, fetchRequest.Topics.Sum(td => td.Partitions.Length), _broker.Host, _broker.Port, _broker.NodeId);
                        fetch = await _protocol.Fetch(fetchRequest, _broker.Conn);
                        EtwTrace.Log.FetcherFetchResponse(_id);

                        // if any TopicPartitions have an error, fail them with the Cluster.
                        fetch.Topics.SelectMany(t => t.Partitions.Select(p => new PartitionStateChangeEvent(t.Topic, p.Partition, p.ErrorCode)))
                            .Where(ps => !ps.ErrorCode.IsSuccess())
                            .ForEach(ps => _cluster.NotifyPartitionStateChange(ps));
                        
                        if (_log.IsDebugEnabled && fetch.Topics.Any(t=>t.Partitions.Any(p=>p.Messages.Length > 0)))
                            _log.Debug("#{0}: got FetchResponse from {2} with messages: {1}", _id, _broker.Conn, fetch.ToString(true));
                    }
                    //catch (TaskCanceledException)
                    //{
                    //    // Usually reason of fetch to time out is broker closing Tcp socket.
                    //    // Due to Tcp specifics, there are situations when closed connection can not be detected, 
                    //    // thus we need to implement timeout to detect it and restart connection.
                    //    _log.Info("#{0} Fetch timed out {1}", _id, this);

                    //    // Continue so that socket exception happen and handle exception
                    //    // in uniform way
                    //    continue;
                    //}
                    catch (ObjectDisposedException e)
                    {
                        if (!_cancel.IsCancellationRequested)
                        {
                            _log.Debug("#{0} connection closed", _id);
                            observer.OnError(e);
                            return;
                        }
                        
                        break;
                    }
                    catch (CorrelationLoopException e)
                    {
                        if (!_cancel.IsCancellationRequested)
                        {
                            _log.Debug("#{0} connection closed", _id);
                            observer.OnError(e);
                            return;
                        }
                        break;
                    }
                    catch (SocketException e)
                    {
                        if (!_cancel.IsCancellationRequested)
                        {
                            _log.Info(e, "#{0} Connection failed. {1}", _id, e.Message);
                            observer.OnError(e);
                            return;
                        }
                        break;
                    }
                    catch (Exception e)
                    {
                        if (!_cancel.IsCancellationRequested)
                        {
                            _log.Error(e, "#{0} Fetcher failed", _id);
                            observer.OnError(e);
                            return;
                        }
                        break;
                    }

                    // if timeout, we got empty response
                    if (fetch.Topics.Any(t => t.Partitions.Any(p => p.Messages.Length > 0))) 
                    { 
                        observer.OnNext(fetch);
                    }
                }

                _log.Info("Cancellation Requested. Shutting Down.");
                observer.OnCompleted();
            });
        }