Example #1
0
        private async Task SendTApplicationExceptionAsync(
            TApplicationException x,
            IChannelHandlerContext ctx,
            ThriftMessage request,
            long responseSequenceId,
            TNiftyTransport requestTransport,
            TProtocol inProtocol,
            TProtocol outProtocol)
        {
            if (ctx.Channel.Open)
            {
                try
                {
                    TMessage message = inProtocol.ReadMessageBegin();
                    outProtocol.WriteMessageBegin(new TMessage(message.Name, TMessageType.Exception, message.SeqID));
                    x.Write(outProtocol);
                    outProtocol.WriteMessageEnd();
                    requestTransport.setTApplicationException(x);
                    outProtocol.Transport.Flush();
                    //unrelease on requestTransport dispose;

                    ThriftMessage response = request.MessageFactory.Invoke(requestTransport.OutBuffer);
                    await WriteResponseAsync(ctx, response, responseSequenceId, DispatcherContext.IsResponseOrderingRequired(ctx));
                }
                catch (TException ex)
                {
                    OnDispatchException(ctx, ex);
                }
            }
        }
Example #2
0
        private void CheckResponseOrderingRequirements(IChannelHandlerContext ctx, ThriftMessage message)
        {
            bool messageRequiresOrderedResponses = message.IsOrderedResponsesRequired;

            if (!DispatcherContext.IsResponseOrderingRequirementInitialized(ctx))
            {
                // This is the first request. This message will decide whether all responses on the
                // channel must be strictly ordered, or whether out-of-order is allowed.
                DispatcherContext.SetResponseOrderingRequired(ctx, messageRequiresOrderedResponses);
            }
            else if (messageRequiresOrderedResponses != DispatcherContext.IsResponseOrderingRequired(ctx))
            {
                // This is not the first request. Verify that the ordering requirement on this message
                // is consistent with the requirement on the channel itself.
                throw new NiftyException("Every message on a single channel must specify the same requirement for response ordering");
            }
        }
Example #3
0
        private long BlockReadingForOrderReponse(IChannelHandlerContext ctx)
        {
            long requestSequenceId = Interlocked.Increment(ref _dispatcherSequenceId);

            if (DispatcherContext.IsResponseOrderingRequired(ctx))
            {
                lock (_responseMap)
                {
                    // Limit the number of pending responses (responses which finished out of order, and are
                    // waiting for previous requests to be finished so they can be written in order), by
                    // blocking further channel reads. Due to the way Netty frame decoders work, this is more
                    // of an estimate than a hard limit. Netty may continue to decode and process several
                    // more requests that were in the latest read, even while further reads on the channel
                    // have been blocked.
                    if (requestSequenceId > Interlocked.Read(ref _lastResponseWrittenId) + _queuedResponseLimit &&
                        !DispatcherContext.IsChannelReadBlocked(ctx))
                    {
                        DispatcherContext.BlockChannelReads(ctx);
                    }
                }
            }

            return(requestSequenceId);
        }
Example #4
0
        private async Task ProcessRequestAsync(
            long requestSequenceId,
            IChannelHandlerContext ctx,
            ThriftMessage message,
            TNiftyTransport messageTransport,
            TProtocol inProtocol,
            TProtocol outProtocol)
        {
            //Task.Run(() =>
            //{
            try
            {
                AtomicBoolean responseSent = new AtomicBoolean(false);
                // Use AtomicReference as a generic holder class to be able to mark it final
                // and pass into inner classes. Since we only use .get() and .set(), we don't
                // actually do any atomic operations.
                AtomicReference <ITimeout> expireTimeout = new AtomicReference <ITimeout>(null);
                try
                {
                    try
                    {
                        long timeRemaining = 0;
                        long timeElapsed   = (DateTime.UtcNow.Ticks - message.ProcessStartTimeTicks) / 10000;

                        if (_queueTimeoutMillis > 0)
                        {
                            if (timeElapsed >= _queueTimeoutMillis)
                            {
                                String error = "Task stayed on the queue for " + timeElapsed +
                                               " milliseconds, exceeding configured queue timeout of " + _queueTimeoutMillis +
                                               " milliseconds.";
                                _logger.LogWarning(error);
                                TApplicationException taskTimeoutException = new TApplicationException(
                                    ExceptionType.InternalError, error);
                                await SendTApplicationExceptionAsync(taskTimeoutException, ctx, message, requestSequenceId, messageTransport,
                                                                     inProtocol, outProtocol);

                                return;
                            }
                        }
                        else if (_taskTimeoutMillis > 0)
                        {
                            if (timeElapsed >= _taskTimeoutMillis)
                            {
                                String error = "Task stayed on the queue for " + timeElapsed +
                                               " milliseconds, exceeding configured task timeout of " + _taskTimeoutMillis +
                                               " milliseconds.";
                                _logger.LogWarning(error);
                                TApplicationException taskTimeoutException = new TApplicationException(
                                    ExceptionType.InternalError, error);
                                await SendTApplicationExceptionAsync(taskTimeoutException, ctx, message, requestSequenceId, messageTransport,
                                                                     inProtocol, outProtocol);

                                return;
                            }
                            else
                            {
                                timeRemaining = _taskTimeoutMillis - timeElapsed;
                            }
                        }

                        if (timeRemaining > 0)
                        {
                            expireTimeout.Value = _taskTimeoutTimer.NewTimeout(timeout =>
                            {
                                // The immediateFuture returned by processors isn't cancellable, cancel() and
                                // isCanceled() always return false. Use a flag to detect task expiration.
                                if (responseSent.CompareAndSet(false, true))
                                {
                                    TApplicationException ex = new TApplicationException(
                                        ExceptionType.InternalError,
                                        "Task timed out while executing."
                                        );
                                    // Create a temporary transport to send the exception
                                    var duplicateBuffer = message.Buffer.Duplicate();
                                    duplicateBuffer.ResetReaderIndex();
                                    using (TNiftyTransport temporaryTransport = new TNiftyTransport(
                                               ctx.Channel,
                                               duplicateBuffer,
                                               message.TransportType))
                                    {
                                        TProtocolPair protocolPair = _duplexProtocolFactory.GetProtocolPair(
                                            TTransportPair.FromSingleTransport(temporaryTransport));
                                        SendTApplicationExceptionAsync(ex, ctx, message,
                                                                       requestSequenceId,
                                                                       temporaryTransport,
                                                                       protocolPair.InputProtocol,
                                                                       protocolPair.OutputProtocol).GetAwaiter().GetResult();
                                    }
                                }
                            }, TimeSpan.FromMilliseconds(timeRemaining / 10000));
                        }
                        //SSL 部分暂时不处理
                        IConnectionContext connectionContext = ctx.Channel.GetConnectionContext();
                        IRequestContext    requestContext    = new NiftyRequestContext(connectionContext, inProtocol, outProtocol, messageTransport);
                        RequestContexts.SetCurrentContext(requestContext);
                        try
                        {
                            //关键部分:交给 Thrift 来处理二进制。
                            bool result = await _processorFactory.GetProcessor(messageTransport).ProcessAsync(inProtocol, outProtocol, requestContext);

                            DeleteExpirationTimer(expireTimeout.Value);
                            try
                            {
                                // Only write response if the client is still there and the task timeout
                                // hasn't expired.
                                if (ctx.Channel.Active && responseSent.CompareAndSet(false, true))
                                {
                                    ThriftMessage response = message.MessageFactory(
                                        messageTransport.OutBuffer);
                                    await WriteResponseAsync(ctx, response, requestSequenceId,
                                                             DispatcherContext.IsResponseOrderingRequired(ctx));
                                }
                            }
                            catch (Exception t)
                            {
                                this.OnDispatchException(ctx, t);
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(0, ex, "write response to client fault.");
                            DeleteExpirationTimer(expireTimeout.Value);
                            OnDispatchException(ctx, ex);
                        }
                    }
                    finally
                    {
                        RequestContexts.ClearCurrentContext();
                    }
                }
                catch (Exception ex)
                {
                    OnDispatchException(ctx, ex);
                    ex.ThrowIfNecessary();
                }
            }
            catch (Exception ex)
            {
                ex.ThrowIfNecessary();
            }

            //});
        }