/// <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); }
/// <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>()); }
/// <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>()); }
private void AddAsyncRequestItemToResponseQueue(AsyncRequestItem requestItem) { if (requestItem == null) { return; } if (_requestsByCorrelation.TryAdd(requestItem.CorrelationId, requestItem) == false) { throw new KafkaException("Failed to register request for async response."); } }
private void AddAsyncRequestItemToResponseQueue(AsyncRequestItem requestItem) { if (requestItem == null) { return; } requestItem.CreatedOnUtc = DateTime.UtcNow; if (_requestIndex.TryAdd(requestItem.CorrelationId, requestItem) == false) { throw new ApplicationException("Failed to register request for async response."); } }
/// <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 IRequest to send to the kafka servers.</param> /// <param name="context">The context for the request.</param> /// <param name="token">Cancellation token used to cancel the transfer.</param> /// <returns></returns> public async Task <T> SendAsync <T>(IRequest <T> request, CancellationToken token, IRequestContext context = null) where T : class, IResponse { var version = context?.ApiVersion; if (!version.HasValue) { version = await GetVersionAsync(request.ApiKey, token).ConfigureAwait(false); } context = new RequestContext(NextCorrelationId(), version, context?.ClientId, context?.Encoders ?? _configuration.Encoders, context?.ProtocolType ?? request.ProtocolType, context?.OnProduceRequestMessages ?? _configuration.OnProduceRequestMessages); var payload = KafkaEncoder.Encode(context, request); _log.Info(() => LogEvent.Create($"Sending {request.ApiKey} with correlation id {context.CorrelationId} (v {version.GetValueOrDefault()}, {payload.Buffer.Length} bytes) to {Endpoint}")); _log.Debug(() => LogEvent.Create($"-----> {request.ApiKey} with correlation id {context.CorrelationId} to {Endpoint}\n{request.ToFormattedString()}")); if (!request.ExpectResponse) { await _socket.WriteAsync(payload, token).ConfigureAwait(false); return(default(T)); } using (var asyncRequest = new AsyncRequestItem(context.CorrelationId, request.ApiKey, _configuration.RequestTimeout)) { try { AddAsyncRequestItemToResponseQueue(asyncRequest); ExceptionDispatchInfo exceptionDispatchInfo = null; try { await _socket.WriteAsync(payload, token).ConfigureAwait(false); } catch (Exception ex) { exceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex); } asyncRequest.MarkRequestAsSent(exceptionDispatchInfo, TriggerMessageTimeout); } catch (OperationCanceledException) { TriggerMessageTimeout(asyncRequest); } var response = await asyncRequest.ReceiveTask.Task.ThrowIfCancellationRequested(token).ConfigureAwait(false); _log.Info(() => LogEvent.Create($"Receiving {request.ApiKey} with correlation id {context.CorrelationId} (v {version.GetValueOrDefault()}, {response.Length} bytes) from {Endpoint}")); var result = KafkaEncoder.Decode <T>(context, response); _log.Debug(() => LogEvent.Create($"<------- {request.ApiKey} with correlation id {context.CorrelationId} from {Endpoint}\n{result.ToFormattedString()}")); return(result); } }
/// <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>()); }
private void TriggerMessageTimeout(AsyncRequestItem asyncRequestItem) { if (asyncRequestItem == null) { return; } AsyncRequestItem request; _requestsByCorrelation.TryRemove(asyncRequestItem.CorrelationId, out request); if (_disposeToken.IsCancellationRequested) { asyncRequestItem.ReceiveTask.TrySetException(new ObjectDisposedException("The object is being disposed and the connection is closing.")); } else { asyncRequestItem.ReceiveTask.TrySetException(new TimeoutException($"Timeout expired after {asyncRequestItem.Timeout.TotalMilliseconds} ms.")); } }
private void TriggerMessageTimeout(AsyncRequestItem asyncRequestItem) { if (asyncRequestItem == null) { return; } AsyncRequestItem request; _requestIndex.TryRemove(asyncRequestItem.CorrelationId, out request); //just remove it from the index if (_disposeToken.IsCancellationRequested) { asyncRequestItem.ReceiveTask.TrySetException( new ObjectDisposedException("The object is being disposed and the connection is closing.")); } else { asyncRequestItem.ReceiveTask.TrySetException(new ResponseTimeoutException( string.Format("Timeout Expired. Client failed to receive a response from server after waiting {0}ms.", _responseTimeoutMS))); } }
/// <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()); }
private void TriggerMessageTimeout(AsyncRequestItem asyncRequestItem) { if (asyncRequestItem == null) { return; } AsyncRequestItem request; //just remove it from the index _requestIndex.TryRemove(asyncRequestItem.CorrelationId, out request); if (_disposeToken.IsCancellationRequested) { asyncRequestItem.ReceiveTask.TrySetException( new ObjectDisposedException("The object is being disposed and the connection is closing.")); } else { asyncRequestItem.ReceiveTask.TrySetException(new ResponseTimeoutException( string.Format("Timeout reached for endpoint {0} (after waiting {1})", _client.Endpoint, _responseTimeoutMs))); } }