From 99fc7e4e50e6b647cb441665ab43e6e0d2f6a22e Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Sat, 19 Sep 2015 15:26:21 -0700 Subject: [PATCH] Moving the Start/Stop logic into Frame. Also formalizes the relationship between the function's Task and how it relates to graceful shutdown. Specifically how it relates to finishing the requests currently in progress. --- .../Http/Connection.cs | 2 +- .../Http/Frame.cs | 54 ++++++++++++++++--- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs index 9d091b752a..def246b92b 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Connection.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http public void Start() { Log.ConnectionStart(_connectionId); - Task.Run(_frame.ProcessFraming); + _frame.Start(); _socket.ReadStart(_allocCallback, _readCallback, this); } diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index 48640b0776..2387d8de65 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -31,8 +31,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders(); private List, object>> _onStarting; + private List, object>> _onCompleted; + private bool _requestProcessingStarted; + private bool _requestProcessingStopping; + private Task _requestProcessingTask; + private bool _responseStarted; private bool _keepAlive; private bool _autoChunk; @@ -99,14 +104,47 @@ namespace Microsoft.AspNet.Server.Kestrel.Http _responseHeaders.HeaderDate = DateTime.UtcNow.ToString("r"); } - public async Task ProcessFraming() + /// + /// Called once by Connection class to begin the RequestProcessingAsync loop. + /// + public void Start() + { + if (!_requestProcessingStarted) + { + _requestProcessingStarted = true; + _requestProcessingTask = Task.Run(RequestProcessingAsync); + } + } + + /// + /// Should be called when the server wants to initiate a shutdown. The Task returned will + /// become complete when the RequestProcessingAsync function has exited. It is expected that + /// Stop will be called on all active connections, and Task.WaitAll() will be called on every + /// return value. + /// + public Task Stop() + { + if (!_requestProcessingStopping) + { + _requestProcessingStopping = true; + } + return _requestProcessingTask ?? TaskUtilities.CompletedTask; + } + + /// + /// Primary loop which consumes socket input, parses it for protocol framing, and invokes the + /// application delegate for as long as the socket is intended to remain open. + /// The resulting Task from this loop is preserved in a field which is used when the server needs + /// to drain and close all currently active connections. + /// + public async Task RequestProcessingAsync() { try { var terminated = false; - while (!terminated) + while (!terminated && !_requestProcessingStopping) { - while (!terminated && !TakeStartLine(SocketInput)) + while (!terminated && !_requestProcessingStopping && !TakeStartLine(SocketInput)) { terminated = SocketInput.RemoteIntakeFin; if (!terminated) @@ -115,7 +153,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http } } - while (!terminated && !TakeMessageHeaders(SocketInput)) + while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput)) { terminated = SocketInput.RemoteIntakeFin; if (!terminated) @@ -124,7 +162,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http } } - if (!terminated) + if (!terminated && !_requestProcessingStopping) { MessageBody = MessageBody.For(HttpVersion, _requestHeaders, this); _keepAlive = MessageBody.RequestKeepAlive; @@ -163,7 +201,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http } catch (Exception ex) { - Log.LogVerbose("Connection processing ended abnormally", ex); + Log.LogWarning("Connection processing ended abnormally", ex); } finally { @@ -178,9 +216,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http // Dispose socket ConnectionControl.End(ProduceEndType.SocketDisconnect); } - catch(Exception ex) + catch (Exception ex) { - Log.LogVerbose("Connection shutdown abnormally", ex); + Log.LogWarning("Connection shutdown abnormally", ex); } } }