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); } } }
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"); } }
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); }
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(); } //}); }