/// <summary> /// /// </summary> /// <param name="ctx"></param> /// <param name="message"></param> protected override void ChannelRead0(IChannelHandlerContext ctx, ThriftMessage message) { message.ProcessStartTimeTicks = DateTime.UtcNow.Ticks; CheckResponseOrderingRequirements(ctx, message); TNiftyTransport messageTransport = new TNiftyTransport(ctx.Channel, message, true); TTransportPair transportPair = TTransportPair.FromSingleTransport(messageTransport); TProtocolPair protocolPair = this._duplexProtocolFactory.GetProtocolPair(transportPair); TProtocol inProtocol = protocolPair.InputProtocol; TProtocol outProtocol = protocolPair.OutputProtocol; long requestSequenceId = BlockReadingForOrderReponse(ctx); IByteBuffer buffer = message.Buffer; buffer.Retain(); _factory.StartNew(() => ProcessRequestAsync(requestSequenceId, ctx, message, messageTransport, inProtocol, outProtocol) .ContinueWith(t => { inProtocol.Dispose(); outProtocol.Dispose(); buffer.Release(); messageTransport?.Dispose(); })); }
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(); } //}); }