/// <exception cref="Exception">A delegate callback throws an exception.</exception>
        /// <exception cref="NullReferenceException">The address of <paramref name="location" /> is a null pointer. </exception>
        public async Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            T result;

            if (typeof(T) == typeof(ProduceResponse))
            {
                Interlocked.Increment(ref ProduceRequestCallCount);
                result = (T)((object)await ProduceResponseFunction());
            }
            else if (typeof(T) == typeof(MetadataResponse))
            {
                Interlocked.Increment(ref MetadataRequestCallCount);
                result = (T)(object) await MetadataResponseFunction();
            }
            else if (typeof(T) == typeof(OffsetResponse))
            {
                Interlocked.Increment(ref OffsetRequestCallCount);
                result = (T)(object) await OffsetResponseFunction();
            }
            else if (typeof(T) == typeof(FetchResponse))
            {
                Interlocked.Increment(ref FetchRequestCallCount);
                result = (T)(object) await FetchResponseFunction();
            }
            else
            {
                throw new Exception("no found implementation");
            }
            var resultlist = new List <T>();

            resultlist.Add(result);
            return(resultlist);
        }
Example #2
0
        /// <summary>
        /// Send kafka payload to server and receive a task event when response is received.
        /// </summary>
        /// <typeparam name="T">A Kafka response object return by decode function.</typeparam>
        /// <param name="request">The IKafkaRequest to send to the kafka servers.</param>
        /// <returns></returns>
        public async Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //assign unique correlationId
            request.CorrelationId = NextCorrelationId();

            //if response is expected, register a receive data task and send request
            if (request.ExpectResponse)
            {
                var asyncRequest = new AsyncRequestItem(request.CorrelationId);

                try
                {
                    AddAsyncRequestItemToResponseQueue(asyncRequest);

                    await SendAsync(request.Encode()).ConfigureAwait(false);
                }
                catch (OperationCanceledException ex)
                {
                    TriggerMessageTimeout(asyncRequest);
                }

                var response = await asyncRequest.ReceiveTask.Task.ConfigureAwait(false);

                return(request.Decode(response).ToList());
            }


            //no response needed, just send
            await SendAsync(request.Encode()).ConfigureAwait(false);

            //TODO should this return a response of success for request?
            return(new List <T>());
        }
Example #3
0
        /// <summary>
        /// Send kafka payload to server and receive a task event when response is received.
        /// </summary>
        /// <typeparam name="T">A Kafka response object return by decode function.</typeparam>
        /// <param name="request">The IKafkaRequest to send to the kafka servers.</param>
        /// <returns></returns>
        public Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //assign unique correlationId
            request.CorrelationId = NextCorrelationId();

            var tcs         = new TaskCompletionSource <List <T> >();
            var asynRequest = new AsyncRequestItem(request.CorrelationId);

            asynRequest.ReceiveTask.Task.ContinueWith(data =>
            {
                try
                {
                    var response = request.Decode(data.Result);
                    tcs.SetResult(response.ToList());

                    //TODO should we check for errors type here and throw?
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
            });

            if (_requestIndex.TryAdd(request.CorrelationId, asynRequest) == false)
            {
                throw new ApplicationException("Failed to register request for async response.");
            }

            SendAsync(request.Encode());

            return(tcs.Task);
        }
Example #4
0
        /// <summary>
        /// Send kafka payload to server and receive a task event when response is received.
        /// </summary>
        /// <typeparam name="T">A Kafka response object return by decode function.</typeparam>
        /// <param name="request">The IKafkaRequest to send to the kafka servers.</param>
        /// <returns></returns>
        public async Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //assign unique correlationId
            request.CorrelationId = NextCorrelationId();

            //if response is expected, register a receive data task and send request
            if (request.ExpectResponse)
            {
                var asyncRequest = new AsyncRequestItem(request.CorrelationId);

                if (_requestIndex.TryAdd(request.CorrelationId, asyncRequest) == false)
                {
                    throw new ApplicationException("Failed to register request for async response.");
                }

                SendAsync(request.Encode());

                var response = await asyncRequest.ReceiveTask.Task.ConfigureAwait(false);

                return(request.Decode(response).ToList());
            }


            //no response needed, just send
            await SendAsync(request.Encode()).ConfigureAwait(false);

            //TODO should this return a response of success for request?
            return(new List <T>());
        }
 /// <summary>
 /// Encode the common head for kafka request.
 /// </summary>
 /// <returns>KafkaMessagePacker with header populated</returns>
 /// <remarks>Format: (hhihs) </remarks>
 public static KafkaMessagePacker EncodeHeader <T>(IKafkaRequest <T> request)
 {
     return(new KafkaMessagePacker()
            .Pack(((Int16)request.ApiKey))
            .Pack(ApiVersion)
            .Pack(request.CorrelationId)
            .Pack(request.ClientId, StringPrefixEncoding.Int16));
 }
Example #6
0
        /// <summary>
        /// Encode the common head for kafka request.
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <remarks>Format: (hhihs) </remarks>
        public static byte[] EncodeHeader <T>(IKafkaRequest <T> request)
        {
            var message = new WriteByteStream();

            message.Pack(((Int16)request.ApiKey).ToBytes(),
                         ApiVersion.ToBytes(),
                         request.CorrelationId.ToBytes(),
                         request.ClientId.ToInt16SizedBytes());

            return(message.Payload());
        }
Example #7
0
        /// <summary>
        /// Send kafka payload to server and receive a task event when response is received.
        /// </summary>
        /// <typeparam name="T">A Kafka response object return by decode function.</typeparam>
        /// <param name="request">The IKafkaRequest to send to the kafka servers.</param>
        /// <returns></returns>
        public async Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //assign unique correlationId
            request.CorrelationId = NextCorrelationId();

            var asyncRequest = new AsyncRequestItem(request.CorrelationId);

            if (_requestIndex.TryAdd(request.CorrelationId, asyncRequest) == false)
            {
                throw new ApplicationException("Failed to register request for async response.");
            }

            await SendAsync(request.Encode());

            var response = await asyncRequest.ReceiveTask.Task;

            return(request.Decode(response).ToList());
        }
        /// <summary>
        /// Send kafka payload to server and receive a task event when response is received.
        /// </summary>
        /// <typeparam name="T">A Kafka response object return by decode function.</typeparam>
        /// <param name="request">The IKafkaRequest to send to the kafka servers.</param>
        /// <returns></returns>

        public async Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //assign unique correlationId
            request.CorrelationId = NextCorrelationId();

            _log.DebugFormat("Entered SendAsync for CorrelationId:{0} Connection:{1} ", request.CorrelationId, Endpoint);
            //if response is expected, register a receive data task and send request
            if (request.ExpectResponse)
            {
                using (var asyncRequest = new AsyncRequestItem(request.CorrelationId))
                {
                    try
                    {
                        AddAsyncRequestItemToResponseQueue(asyncRequest);
                        ExceptionDispatchInfo exceptionDispatchInfo = null;

                        try
                        {
                            await _client.WriteAsync(request.Encode()).ConfigureAwait(false);
                        }
                        catch (Exception ex)
                        {
                            exceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex);
                        }

                        asyncRequest.MarkRequestAsSent(exceptionDispatchInfo, _responseTimeoutMs, TriggerMessageTimeout);
                    }
                    catch (OperationCanceledException)
                    {
                        TriggerMessageTimeout(asyncRequest);
                    }

                    var response = await asyncRequest.ReceiveTask.Task.ConfigureAwait(false);

                    return(request.Decode(response).ToList());
                }
            }

            //no response needed, just send
            await _client.WriteAsync(request.Encode()).ConfigureAwait(false);

            //TODO should this return a response of success for request?
            return(new List <T>());
        }
        public Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //start a thread to handle the request and return
            var task = new Task <List <T> >(() =>
            {
                if (typeof(T) == typeof(ProduceResponse))
                {
                    ProduceRequestCallCount++;
                    return(new List <T> {
                        (T)(object)ProduceResponseFunction()
                    });
                }
                else if (typeof(T) == typeof(MetadataResponse))
                {
                    MetadataRequestCallCount++;
                    return(new List <T> {
                        (T)(object)MetadataResponseFunction()
                    });
                }
                else if (typeof(T) == typeof(OffsetResponse))
                {
                    OffsetRequestCallCount++;
                    return(new List <T> {
                        (T)(object)OffsetResponseFunction()
                    });
                }
                else if (typeof(T) == typeof(FetchResponse))
                {
                    FetchRequestCallCount++;
                    return(new List <T> {
                        (T)(object)FetchResponseFunction()
                    });
                }

                return(null);
            });

            task.Start();
            return(task);
        }
Example #10
0
        /// <summary>
        /// Send kafka payload to server and receive a task event when response is received.
        /// </summary>
        /// <typeparam name="T">A Kafka response object return by decode function.</typeparam>
        /// <param name="request">The IKafkaRequest to send to the kafka servers.</param>
        /// <returns></returns>
        public async Task <List <T> > SendAsync <T>(IKafkaRequest <T> request)
        {
            //assign unique correlationId
            request.Correlation = NextCorrelationId();

            var asyncRequest = new AsyncRequestItem(request.Correlation);

            if (_requestIndex.TryAdd(request.Correlation, asyncRequest) == false)
            {
                throw new ApplicationException("Failed to register request for async response.");
            }

            // Encode the request into a stream
            var stream = new BinaryStream();

            request.Encode(stream);

            // Write to the socket
            await _client.WriteAsync(stream);

            var response = await asyncRequest.ReceiveTask.Task;

            return(request.Decode(response).ToList());
        }
        /// <exception cref="InvalidTopicMetadataException">Thrown if the returned metadata for the given topic is invalid or missing</exception>
        /// <exception cref="InvalidPartitionException">Thrown if the give partitionId does not exist for the given topic.</exception>
        /// <exception cref="ServerUnreachableException">Thrown if none of the default brokers can be contacted</exception>
        /// <exception cref="ResponseTimeoutException">Thrown if there request times out</exception>
        /// <exception cref="BrokerConnectionException">Thrown in case of network error contacting broker (after retries)</exception>
        /// <exception cref="KafkaApplicationException">Thrown in case of an unexpected error in the request</exception>
        /// <exception cref="FormatException">Thrown in case the topic name is invalid</exception>
        public async Task <T> SendProtocolRequest <T>(IKafkaRequest <T> request, string topic, int partition) where T : class, IBaseResponse
        {
            ValidateTopic(topic);
            T   response  = null;
            int retryTime = 0;

            while (retryTime < _maxRetry)
            {
                bool needToRefreshTopicMetadata     = false;
                ExceptionDispatchInfo exceptionInfo = null;
                string errorDetails = "";

                try
                {
                    await _brokerRouter.RefreshMissingTopicMetadata(topic);

                    //find route it can chage after Metadata Refresh
                    var route     = _brokerRouter.SelectBrokerRouteFromLocalCache(topic, partition);
                    var responses = await route.Connection.SendAsync(request).ConfigureAwait(false);

                    response = responses.FirstOrDefault();

                    //this can happened if you send ProduceRequest with ack level=0
                    if (response == null)
                    {
                        return(null);
                    }

                    var error = (ErrorResponseCode)response.Error;
                    if (error == ErrorResponseCode.NoError)
                    {
                        return(response);
                    }

                    //It means we had an error
                    errorDetails = error.ToString();
                    needToRefreshTopicMetadata = CanRecoverByRefreshMetadata(error);
                }
                catch (ResponseTimeoutException ex)
                {
                    exceptionInfo = ExceptionDispatchInfo.Capture(ex);
                }
                catch (BrokerConnectionException ex)
                {
                    exceptionInfo = ExceptionDispatchInfo.Capture(ex);
                }
                catch (NoLeaderElectedForPartition ex)
                {
                    exceptionInfo = ExceptionDispatchInfo.Capture(ex);
                }
                catch (LeaderNotFoundException ex)//the numbar partition of can be change
                {
                    exceptionInfo = ExceptionDispatchInfo.Capture(ex);
                }

                if (exceptionInfo != null)
                {
                    needToRefreshTopicMetadata = true;
                    errorDetails = exceptionInfo.SourceException.GetType().Name;
                }

                retryTime++;
                bool hasMoreRetry = retryTime < _maxRetry;

                _brokerRouter.Log.WarnFormat("ProtocolGateway error sending request, retrying (attempt number {0}): {1}", retryTime, errorDetails);
                if (needToRefreshTopicMetadata && hasMoreRetry)
                {
                    await _brokerRouter.RefreshTopicMetadata(topic).ConfigureAwait(false);
                }
                else
                {
                    _brokerRouter.Log.ErrorFormat("ProtocolGateway sending request failed");

                    // If an exception was thrown, we want to propagate it
                    if (exceptionInfo != null)
                    {
                        exceptionInfo.Throw();
                    }

                    // Otherwise, the error was from Kafka, throwing application exception
                    throw new KafkaApplicationException("FetchResponse received an error from Kafka: {0}", errorDetails)
                          {
                              ErrorCode = response.Error
                          };
                }
            }

            return(response);
        }
Example #12
0
        /// <exception cref="InvalidTopicMetadataException">Thrown if the returned metadata for the given topic is invalid or missing</exception>
        /// <exception cref="InvalidPartitionException">Thrown if the give partitionId does not exist for the given topic.</exception>
        /// <exception cref="ServerUnreachableException">Thrown if none of the default brokers can be contacted</exception>
        /// <exception cref="ResponseTimeoutException">Thrown if there request times out</exception>
        /// <exception cref="SocketException">Thrown in case of network error contacting broker (after retries)</exception>
        /// <exception cref="KafkaApplicationException">Thrown in case of an unexpected error in the request</exception>
        /// <exception cref="FormatException">Thrown in case the topic name is invalid</exception>
        public async Task <T> SendProtocolRequest <T>(IKafkaRequest <T> request, string topic, int partition) where T : class, IBaseResponse
        {
            ValidateTopic(topic);
            T   response  = null;
            int retryTime = 0;

            while (retryTime < _maxRetry)
            {
                bool needToRefreshTopicMetadata;
                ExceptionDispatchInfo exception = null;
                try
                {
                    await _brokerRouter.RefreshMissingTopicMetadata(topic);

                    //find route it can chage after Metadata Refresh
                    var route     = _brokerRouter.SelectBrokerRouteFromLocalCache(topic, partition);
                    var responses = await route.Connection.SendAsync(request);

                    response = responses.FirstOrDefault();

                    //this can happened if you send ProduceRequest with ack level=0
                    if (response == null)
                    {
                        return(null);
                    }

                    var error = (ErrorResponseCode)response.Error;
                    if (error == ErrorResponseCode.NoError)
                    {
                        return(response);
                    }

                    //It means we had an error

                    needToRefreshTopicMetadata = CanRecoverByRefreshMetadata(error);
                }
                catch (ResponseTimeoutException ex)
                {
                    exception = ExceptionDispatchInfo.Capture(ex);
                    needToRefreshTopicMetadata = true;
                }
                catch (SocketException ex)
                {
                    exception = ExceptionDispatchInfo.Capture(ex);
                    needToRefreshTopicMetadata = true;
                }
                bool hasMoreRetry = retryTime + 1 < _maxRetry;

                if (needToRefreshTopicMetadata && hasMoreRetry)
                {
                    retryTime++;
                    await _brokerRouter.RefreshTopicMetadata(topic);
                }
                else
                {
                    if (exception != null)
                    {
                        exception.Throw();
                    }

                    throw new KafkaApplicationException("FetchResponse returned error condition.  ErrorCode:{0}", response.Error)
                          {
                              ErrorCode = response.Error
                          };
                }
            }

            throw new KafkaApplicationException("FetchResponse returned error condition.  ErrorCode:{0}", response.Error);
        }