Skip to content

Add ISocketConnectionContextFactory #34769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Aug 13, 2021
Merged

Add ISocketConnectionContextFactory #34769

merged 32 commits into from
Aug 13, 2021

Conversation

HaoK
Copy link
Member

@HaoK HaoK commented Jul 27, 2021

Fixes #34522

Still trying to figure out why shutdown tests are failing, but want to see a full ci run

@ghost ghost added the area-runtime label Jul 27, 2021
@davidfowl
Copy link
Member

This changes the memory pool and socketsender lifetime. We still want one of those per endpoint.

@HaoK
Copy link
Member Author

HaoK commented Jul 27, 2021

Guessing that's why the shutdown tests are all failing :) Yeah the analogy I used during standup today is that I feel like I've transplanted a kidney into a lung cavity, still figuring out how stuff works, thanks for the early feedback.

@HaoK
Copy link
Member Author

HaoK commented Jul 27, 2021

This changes the memory pool and socketsender lifetime. We still want one of those per endpoint.

It wasn't clear to me how best to flow what is in the settings to the new SocketConnectionContextFactory when the API only had Create(Socket, SocketConnectionOptions). internal properties on the SocketConnectionOptions?

@HaoK HaoK requested a review from halter73 July 28, 2021 18:34
@HaoK
Copy link
Member Author

HaoK commented Jul 28, 2021

Looks like all the tests are passing now except for the unix domain sockets, not sure what's different about those

There's a socket exception for the 2 unix socket tests: "An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call."

(Looks like this is caused by accessing socket.NoDelay on unix sockets)

@HaoK
Copy link
Member Author

HaoK commented Jul 28, 2021

I'm assuming I should also update

to use this new abstraction? At this point I might well update the SocketConncection ctor to just take the new options class

@halter73
Copy link
Member

I'm assuming I should also update [SocketConnectionFactory.cs] to use this new abstraction?

I don't think so. This abstraction is for use by third-party transports not for allowing people to create their own ConnectionContexts from Sockets. I don't think anyone asked for the latter, so I'd rather not support that if we don't have to. I don't think SocketTransportFactory should consume the (I)SocketConnectionContextFactory either.

@HaoK
Copy link
Member Author

HaoK commented Jul 29, 2021

I don't think anyone asked for the latter, so I'd rather not support that if we don't have to. I don't think SocketTransportFactory should consume the (I)SocketConnectionContextFactory either.

Okay I defer to you guys, just from the general purpose naming its a bit surprising that we wouldn't use it everywhere we create SocketConnectionContexts

@halter73
Copy link
Member

Okay I defer to you guys, just from the general purpose naming its a bit surprising that we wouldn't use it everywhere we create SocketConnectionContexts

That's partly why I like removing the interface and not registering it with the IServiceCollection in UseKestrel(). In many cases, I expect it won't be registered as a service at all, but instead newed-up by a custom IConnectionListenerFactory with services it gets in its constructor.

When I filed the API proposal, I was considering an interface and not the concrete class. So we'll need to add the constructor to the API proposal. I think the ILoggerFactory would be the only parameter though.

@HaoK
Copy link
Member Author

HaoK commented Jul 29, 2021

I don't think SocketTransportFactory should consume the (I)SocketConnectionContextFactory either

Right now the transport factory is who new's up the SocketConnectionListener in Bind so if it doesn't use it, no-one will since the socket connection listener isn't currently getting created from DI no?

@halter73
Copy link
Member

Correct. This isn't for us to use. It's for third-party transports to use. So we'll definitely want to add some tests to make sure it all works end-to-end.

@HaoK
Copy link
Member Author

HaoK commented Jul 29, 2021

That's partly why I like removing the interface and not registering it with the IServiceCollection in UseKestrel(). In many cases, I expect it won't be registered as a service at all, but instead newed-up by a custom IConnectionListenerFactory with services it gets in its constructor.

What's so bad about just treating this as a normal service that is responsible for creating ConnectionContexts from a Socket and SocketConnectionOptions? I'm obviously coming at this from a totally naïve viewpoint...that's what the current naming would have me expect its responsibility is

@halter73
Copy link
Member

We have a lot more flexibility in the future we we don't consume the SocketConnectionContextFactory as a service in the socket transport.

If we consume it as a service, that effectively forces us to change a public API any time we want to change the SocketConnection constructor. Sometimes this might be warranted anyway so third-party transports using it always have the same capabilities we do, but that might not always be necessary if we just continue calling the constructor directly with the internal pools we manage and whatnot. I like being able to make this decision on a case-by-case basis rather than be force into it.

Anyone who's willing to do all the work to create a completely custom ConnectionContext from a Socket should just register their own IConnectionListenerFactory and bypass the socket transport completely since they've already done 90% of the work of implementing a custom IConnectionListenerFactory anyway. If someone just wants to decorate the ConnectionContext the socket transport would normally give you, they can use connection middleware and it'd work with any transport.

@halter73
Copy link
Member

I've updated the issue with my current thinking about how the API should look. I should have never made it an interface or called it a service. The reason we decided not to make it a static method as originally proposed is not so it can be replaced and injested by the socket transport, but so it can keep pools around between calls.

@HaoK HaoK changed the title WIP: Add ISocketConnectionContextFactory Add ISocketConnectionContextFactory Aug 11, 2021
@HaoK HaoK requested a review from a team as a code owner August 12, 2021 19:41
@HaoK
Copy link
Member Author

HaoK commented Aug 12, 2021

Pretty clean now, basically net changes look like we moved a bunch of code from the listener -> factory and split the transport options into two classes. Socket tests are green locally so I think this is ready for final review @halter73 @davidfowl

/// <remarks>
/// Defaults to <see cref="Environment.ProcessorCount" /> rounded down and clamped between 1 and 16.
/// </remarks>
public int IOQueueCount { get; set; } = Math.Min(Environment.ProcessorCount, 16);
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this is a breaking change?

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 definitely affected the shipped public api's txt files

Copy link
Member Author

Choose a reason for hiding this comment

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

Code check said no as well: Detected modification to baseline API files. PublicAPI.Shipped.txt files should only be updated after a major release. See /docs/APIBaselines.md for more information.

So back this out and just duplicate this in a new options class?

Copy link
Member

Choose a reason for hiding this comment

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

Yep

Copy link
Member

Choose a reason for hiding this comment

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

I don't think introducing a new base class by itself is a breaking change, but I'm pretty sure moving properties down to the new base class is. https://docs.microsoft.com/en-us/dotnet/core/compatibility/ says "Introducing a new base class" "REQUIRES JUDGMENT".

Copy link
Member Author

Choose a reason for hiding this comment

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

Well I reverted that and just added an internal copy constructor to flow things to the 'base' ContextFactory options

Copy link
Member Author

Choose a reason for hiding this comment

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

So we could do this in a non breaking way by making the properties virtual and override them to call base or something?

Copy link
Member

Choose a reason for hiding this comment

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

What you have is fine. Leave them separate.

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.

This is super clean.

@davidfowl
Copy link
Member

OK @kevin-montrose we re-did the change and make a class that can be created (without DI) that has all of the implementation guts of the transport. To enable your scenario, you can write a custom transport that handles the listening logic on both the incoming server and the server being routed to.

@mconnew for your scenario, we exposed the pipe settings so you can control the thresholds. We don't let you change the IDuplexPipe implementation before we read from the socket though. Hopefully that isn't a huge blocker. This should enable you to write a custom transport in CoreWCF without losing the behavior or performance enhancements we continue to make in the transport.

@HaoK HaoK merged commit ff51fd7 into main Aug 13, 2021
@HaoK HaoK deleted the haok/sockets branch August 13, 2021 04:02
@ghost ghost added this to the 6.0-rc1 milestone Aug 13, 2021
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add method to create ConnectionContext from Socket
5 participants