Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Commit 14f020c

Browse files
authored
Improve tracking of connection lifetime (#2646)
1 parent 35d9590 commit 14f020c

File tree

2 files changed

+23
-24
lines changed

2 files changed

+23
-24
lines changed

src/Kestrel.Core/Internal/HttpConnection.cs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using System.Threading;
1212
using System.Threading.Tasks;
1313
using Microsoft.AspNetCore.Connections;
14-
using Microsoft.AspNetCore.Connections.Features;
1514
using Microsoft.AspNetCore.Hosting.Server;
1615
using Microsoft.AspNetCore.Http.Features;
1716
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
@@ -30,6 +29,7 @@ public class HttpConnection : ITimeoutControl, IConnectionTimeoutFeature
3029

3130
private readonly HttpConnectionContext _context;
3231
private readonly TaskCompletionSource<object> _socketClosedTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
32+
private readonly TaskCompletionSource<object> _lifetimeTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
3333

3434
private IList<IAdaptedConnection> _adaptedConnections;
3535
private IDuplexPipe _adaptedTransport;
@@ -53,8 +53,6 @@ public class HttpConnection : ITimeoutControl, IConnectionTimeoutFeature
5353
private int _writeTimingWrites;
5454
private long _writeTimingTimeoutTimestamp;
5555

56-
private Task _lifetimeTask;
57-
5856
public HttpConnection(HttpConnectionContext context)
5957
{
6058
_context = context;
@@ -98,12 +96,7 @@ public HttpConnection(HttpConnectionContext context)
9896

9997
private IKestrelTrace Log => _context.ServiceContext.Log;
10098

101-
public Task StartRequestProcessing<TContext>(IHttpApplication<TContext> application)
102-
{
103-
return _lifetimeTask = ProcessRequestsAsync(application);
104-
}
105-
106-
private async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication)
99+
public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> httpApplication)
107100
{
108101
try
109102
{
@@ -132,9 +125,6 @@ private async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> htt
132125
_adaptedTransport = adaptedPipeline;
133126
}
134127

135-
// Do this before the first await so we don't yield control to the transport until we've
136-
// added the connection to the connection manager
137-
_context.ServiceContext.ConnectionManager.AddConnection(_context.HttpConnectionId, this);
138128
_lastTimestamp = _context.ServiceContext.SystemClock.UtcNow.Ticks;
139129

140130
_context.ConnectionFeatures.Set<IConnectionTimeoutFeature>(this);
@@ -194,7 +184,6 @@ private async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> htt
194184
}
195185
finally
196186
{
197-
_context.ServiceContext.ConnectionManager.RemoveConnection(_context.HttpConnectionId);
198187
DisposeAdaptedConnections();
199188

200189
if (_http1Connection?.IsUpgraded == true)
@@ -204,6 +193,8 @@ private async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> htt
204193

205194
Log.ConnectionStop(ConnectionId);
206195
KestrelEventSource.Log.ConnectionStop(this);
196+
197+
_lifetimeTcs.SetResult(null);
207198
}
208199
}
209200

@@ -269,7 +260,7 @@ public Task StopProcessingNextRequestAsync()
269260
}
270261
}
271262

272-
return _lifetimeTask;
263+
return _lifetimeTcs.Task;
273264
}
274265

275266
public void OnInputOrOutputCompleted()

src/Kestrel.Core/Internal/HttpConnectionMiddleware.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,30 @@ public async Task OnConnectionAsync(ConnectionContext connectionContext)
7373
}
7474

7575
var connection = new HttpConnection(httpConnectionContext);
76+
_serviceContext.ConnectionManager.AddConnection(httpConnectionId, connection);
7677

77-
var processingTask = connection.StartRequestProcessing(_application);
78+
try
79+
{
80+
var processingTask = connection.ProcessRequestsAsync(_application);
7881

79-
connectionContext.Transport.Input.OnWriterCompleted(
80-
(_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
81-
connection);
82+
connectionContext.Transport.Input.OnWriterCompleted(
83+
(_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
84+
connection);
8285

83-
connectionContext.Transport.Output.OnReaderCompleted(
84-
(_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
85-
connection);
86+
connectionContext.Transport.Output.OnReaderCompleted(
87+
(_, state) => ((HttpConnection)state).OnInputOrOutputCompleted(),
88+
connection);
8689

87-
await AsTask(lifetimeFeature.ConnectionClosed);
90+
await AsTask(lifetimeFeature.ConnectionClosed);
8891

89-
connection.OnConnectionClosed();
92+
connection.OnConnectionClosed();
9093

91-
await processingTask;
94+
await processingTask;
95+
}
96+
finally
97+
{
98+
_serviceContext.ConnectionManager.RemoveConnection(httpConnectionId);
99+
}
92100
}
93101

94102
private Task AsTask(CancellationToken token)

0 commit comments

Comments
 (0)