예제 #1
0
        private void WireUpConsumer(IRawConsumer consumer, IConsumerConfiguration cfg)
        {
            consumer.OnMessageAsync = (o, args) =>
            {
                ResponseCompletionSource responseTcs = null;
                return(_errorStrategy.ExecuteAsync(() =>
                {
                    if (_responseDictionary.TryRemove(args.BasicProperties.CorrelationId, out responseTcs))
                    {
                        _logger.LogDebug($"Recived response with correlationId {args.BasicProperties.CorrelationId}.");
                        responseTcs.RequestTimer.Dispose();

                        _errorStrategy.OnResponseRecievedAsync(args, responseTcs);
                        if (responseTcs.Task.IsFaulted)
                        {
                            return _completed;
                        }
                        var response = _serializer.Deserialize(args);
                        responseTcs.TrySetResult(response);
                        return _completed;
                    }
                    _logger.LogWarning($"Unable to find callback for {args.BasicProperties.CorrelationId}.");
                    return _completed;
                }, exception => _errorStrategy.OnResponseRecievedException(consumer, cfg, args, responseTcs, exception)));
            };
        }
예제 #2
0
        private Task <TResponse> SendRequestAsync <TRequest, TResponse>(TRequest message, Guid globalMessageId, RequestConfiguration cfg, IRawConsumer consumer)
        {
            var correlationId  = Guid.NewGuid().ToString();
            var responseSource = new ResponseCompletionSource
            {
                RequestTimer = new Timer(state =>
                {
                    ResponseCompletionSource rcs;
                    if (!_responseDictionary.TryRemove(correlationId, out rcs))
                    {
                        _logger.LogWarning($"Unable to find request timer for {correlationId}.");
                        return;
                    }
                    rcs.RequestTimer?.Dispose();
                    rcs.TrySetException(
                        new TimeoutException($"The request '{correlationId}' timed out after {_config.RequestTimeout.ToString("g")}."));
                }, null, _config.RequestTimeout, new TimeSpan(-1))
            };

            _responseDictionary.TryAdd(correlationId, responseSource);

            consumer.Model.BasicPublish(
                exchange: cfg.Exchange.ExchangeName,
                routingKey: _config.RouteWithGlobalId ? $"{cfg.RoutingKey}.{globalMessageId}" : cfg.RoutingKey,
                basicProperties: _propertiesProvider.GetProperties <TResponse>(p =>
            {
                p.ReplyTo       = cfg.ReplyQueue.QueueName;
                p.CorrelationId = correlationId;
                p.Expiration    = _config.RequestTimeout.TotalMilliseconds.ToString();
                p.Headers.Add(PropertyHeaders.Context, _contextProvider.GetMessageContext(globalMessageId));
            }),
                body: _serializer.Serialize(message)
                );
            return(responseSource.Task.ContinueWith(tResponse =>
            {
                if (tResponse.IsFaulted)
                {
                    throw tResponse.Exception?.InnerException ?? new Exception("Failed to recieve response");
                }
                return (TResponse)tResponse.Result;
            }));
        }
예제 #3
0
        internal Task <TResponse> SendReceiveFrameAsync <TRequest, TResponse>(
            RpcFrameType frameType,
            string operation,
            RpcRequestContext?context,
            TRequest request,
            LightweightSerializers <TRequest, TResponse> serializers,
            int timeout)
            where TRequest : class
        {
            if (TraceEnabled)
            {
                // TODO: Logger.Trace("Begin SendReceiveFrameAsync {Operation}.", operation);
            }

            var tcs = new ResponseCompletionSource <TResponse>(serializers.Serializer, serializers.ResponseSerializer);

            int messageId = this.AddAwaitingResponse(tcs);

            try
            {
                RpcOperationFlags flags = 0;

                var cancellationToken = context != null ? context.CancellationToken : default;
                if (cancellationToken.CanBeCanceled)
                {
                    cancellationToken.Register(() => this.CancelCall(messageId, operation));
                    flags |= RpcOperationFlags.CanCancel;
                }

                var frame = new LightweightRpcFrame(frameType, messageId, operation, flags, (uint)timeout, context?.Headers);

                var writeState = this.BeginWrite(frame);

                var writeTask = this.WriteRequestAsync(request, serializers.RequestSerializer, writeState);
                if (writeTask.IsCompletedSuccessfully)
                {
                    if (timeout == 0 || RpcProxyOptions.RoundTripCancellationsAndTimeouts)
                    {
                        return(tcs.Task);
                    }
                    else
                    {
                        return(AwaitTimeoutResponse(tcs.Task, operation, timeout));
                    }
                }
                else
                {
                    return(AwaitWrite(writeTask, tcs.Task));
                }
            }
            catch (Exception ex)
            {
                this.HandleCallError(messageId, ex);
                throw;
            }

            async Task <TResponse> AwaitTimeoutResponse(Task <TResponse> responseTask, string operation, int timeout)
            {
                var completedTask = await Task.WhenAny(responseTask, Task.Delay(timeout)).ContextFree();

                if (completedTask == responseTask)
                {
                    return(responseTask.AwaiterResult());
                }
                else
                {
                    throw new TimeoutException($"Operation '{operation}' didn't complete within the timeout ({timeout} ms).");
                }
            }

            async Task <TResponse> AwaitWrite(ValueTask writeTask, Task <TResponse> responseTask)
            {
                await writeTask.ContextFree();

                if (timeout == 0 || RpcProxyOptions.RoundTripCancellationsAndTimeouts)
                {
                    return(await responseTask.ContextFree());
                }
                else
                {
                    return(await AwaitTimeoutResponse(responseTask, operation, timeout).ContextFree());
                }
            }
        }