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

Improve testing of Sockets transport #2100

Merged
merged 15 commits into from
Oct 11, 2017
Merged

Improve testing of Sockets transport #2100

merged 15 commits into from
Oct 11, 2017

Conversation

halter73
Copy link
Member

@halter73 halter73 commented Oct 5, 2017

This PR also makes Sockets the default. This will allow us to see the quickly see the impact of selecting the Sockets transport in ServerTests/MusicStore/Entropy/etc.

#1694

return hostBuilder.ConfigureServices(services =>
{
// Don't override an already-configured transport
services.TryAddSingleton<ITransportFactory, SocketTransportFactory>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not call UseSockets()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling UseSockets here would cause UseKestrel override any previously configured transport. This is different than the old behavior with the libuv default, but it makes the TransportSelectors easier to implement.

EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Trasnport.Libuv.FunctionalTests", "test\Kestrel.Transport.Libuv.FunctionalTests\Kestrel.Trasnport.Libuv.FunctionalTests.csproj", "{74032D79-8EA7-4483-BD82-C38370420FFF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Trasnport.Sockets.FunctionalTests", "test\Kestrel.Transport.Sockets.FunctionalTests\Kestrel.Trasnport.Sockets.FunctionalTests.csproj", "{9C7B6B5F-088A-436E-834B-6373EA36DEEE}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: Trasnport


namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{
public interface ISocketTrace : ILogger
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be called ISocketsTrace, given the transport is called Sockets.


namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal
{
public class SocketTrace : ISocketTrace
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this exactly (or almost exactly) the same as LibuvTrace?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Minus a few things.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then how about having a common base class in Transport.Abstractions? Do you think that might not suit future transports?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be a good idea, but it's not 100% clear exactly which log methods belong in the base class. Some transports might not be TCP-based and not have a concept of things like sending vs receiving a FIN.

I created #2101 to discuss this idea further.

// ConnectionRead: Reserved: 3

private static readonly Action<ILogger, string, Exception> _connectionPause =
LoggerMessage.Define<string>(LogLevel.Debug, 4, @"Connection id ""{ConnectionId}"" paused.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't these IDs clash with other IDs? What's the scope of an event ID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IDs match mostly to make the cross-transport tests easier. It's in the "Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" scope, so there shouldn't be any conflicts.

@@ -16,7 +16,9 @@

<ItemGroup>
<ProjectReference Include="..\Kestrel.Core\Kestrel.Core.csproj" />
<ProjectReference Include="..\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
<!-- Even though the Libuv transport is no longer used by default, it's remains for back-compat -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it

test\SystemdActivation\Dockerfile = test\SystemdActivation\Dockerfile
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kestrel.Trasnport.Libuv.FunctionalTests", "test\Kestrel.Transport.Libuv.FunctionalTests\Kestrel.Trasnport.Libuv.FunctionalTests.csproj", "{74032D79-8EA7-4483-BD82-C38370420FFF}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: Trasnport

@@ -223,7 +244,13 @@ private void SetupSendBuffers(ReadableBuffer buffer)
}
finally
{
// Now, complete the input so that no more reads can happen
Input.Complete(error ?? new ConnectionAbortedException());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to do this here? It happens on the input side. It's a bit cleaner than the libuv transport.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/aspnet/KestrelHttpServer/blob/dev/test/Kestrel.FunctionalTests/RequestTests.cs#L1081-L1091

If we don't complete the input with a ConnectionAbortedException here prior to initiating a connection shutdown, the test will close the client half of the connection which will complete the input gracefully.

If something is still trying to read after the output is closed, that's a problem. The connection is aborted at this point. The exact same code is there for libuv: https://github.com/aspnet/KestrelHttpServer/blob/dev/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs#L72-L82

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature is fine I just want it to happen at the "right place" which IMO is the end of the input loop.

https://github.com/aspnet/KestrelHttpServer/blob/dev/src/Kestrel.Transport.Sockets/SocketConnection.cs#L208-L215

Copy link
Member Author

@halter73 halter73 Oct 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you linked to the end of the output loop. Just like the LibuvConnection, SocketConnection completes the input both when the output is closed and the input is closed. This means input is always completed twice in both transports.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Well, it's removed now and we're back to one call to IPipeWriter.Complete(). I'm wondering if we should change the libuv transport as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's easier here since there's 2 async loops

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. If the libuv output loop exits first, it will call uv_close which prevents the read callback from receiving notification of the disconnect.

// Make sure to close the connection only after the input is aborted
// Make sure to close the connection only after the _aborted flag is set.
// Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when
// a BadHttpRequestException is thrown instaed of a TaskCanceledException.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: instead

@davidfowl
Copy link
Member

davidfowl commented Oct 10, 2017

Why is Travis failing?

Copy link
Member

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When Travis passes ..

@@ -40,6 +46,10 @@ internal SocketConnection(Socket socket, SocketTransport transport)
RemotePort = remoteEndPoint.Port;
}

public override PipeFactory PipeFactory { get; }
public override IScheduler InputWriterScheduler => InlineScheduler.Default;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this problematic?

@davidfowl
Copy link
Member

Seems like there are a bunch of legit failures on OSX.

}
finally
{
if (_aborted)
{
error = error ?? new ConnectionAbortedException();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log in the ConnectionAbortedException case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just because the error is being set here, doesn't mean that there is an ongoing call to Request.Body.ReadAsync() for the error to be thrown from. This error always gets set for a server-initiated connection close. If there is an ongoing ReadAsync() call when the server closes the connection, it's because the application called Abort().

We log a disconnect in the Abort() call that sets _aborted flag here. This covers both the libuv and sockets transports.

We could look to changing the log in Http1OutputProducer to make it more clear whether the connection was aborted or closed normally, though this is usually clear when the exception from ReadAsync bubbles up and gets logged.

@halter73 halter73 force-pushed the halter73/sockets branch 2 times, most recently from 9e4ea06 to e918edd Compare October 11, 2017 19:56
@halter73 halter73 merged commit fdb4184 into dev Oct 11, 2017
@halter73 halter73 deleted the halter73/sockets branch October 11, 2017 22:14
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants