-
Notifications
You must be signed in to change notification settings - Fork 633
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
Add docs for the async NIO APIs #2549
Conversation
docs/public-async-nio-apis.md
Outdated
public func configureAsyncHTTP2Pipeline<Output: Sendable>( | ||
mode: NIOHTTP2Handler.ParserMode, | ||
configuration: NIOHTTP2Handler.Configuration = .init(), | ||
position: ChannelPipeline.Position = .last, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should drop the position here because it is a type we cannot make Sendable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @rnro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We almost certainly have to drop it: semantically the only place we can do this is last. What does it mean to add your async channel handlers not last?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine to drop it. The only times when it might be used I can think of are incredibly contrived and it's possible to work around them anyway. So, yeah I'm in favor of dropping the non-sendable footgun.
/// be waited on to retrieve the result of the negotiation. | ||
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public func configureAsyncHTTPServerPipeline<HTTP1ConnectionOutput: Sendable, HTTP2ConnectionOutput: Sendable, HTTP2StreamOutput: Sendable>( | ||
http2Configuration: NIOHTTP2Handler.Configuration = .init(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the HTTP2 parser mode here @rnro?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the function for configuring a server pipeline so the parser mode is hardcoded to .server
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) | ||
public struct AsyncStreamMultiplexer<InboundStreamOutput> { | ||
/// Create a stream channel initialized with the provided closure | ||
public func createStreamChannel<Output: Sendable>(_ initializer: @escaping NIOChannelInitializerWithOutput<Output>) async throws -> Output |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still wondering if we should call this createOutboundStream
this would provide a good balance to the InboundStreamOutput
e.g. cc @rnro
public func createStreamChannel<Output: Sendable>(_ initializer: @escaping NIOChannelInitializerWithOutput<Output>) async throws -> Output | |
public func createOutboundStream<Output: Sendable>(_ initializer: @escaping NIOChannelInitializerWithOutput<Output>) async throws -> Output |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are dropping consistency with the old multiplexer then I think createOutboundStream
is an improvement, but I'm now actually wondering if we should just go for createStream
, do we need to disambiguate against somehow creating an inbound stream? cc @glbrntt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still something which feels a bit vague about how we call createStream
/createOutboundStream
but then hand back the caller basically anything. Our assumption is that they wrapped the channel in the initializer and returned that, which might be fair enough but I'm not sure that the word initializer
conveys all that (new to async-land) responsibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
createStreamChannel
is slightly odd because we don't return aChannel
createOutboundStream
is better, but it's not possible to create inbound streams so I don't think the "outbound" distinction is importantcreateStream
is better still
There's still something which feels a bit vague about how we call createStream/createOutboundStream but then hand back the caller basically anything. Our assumption is that they wrapped the channel in the initializer and returned that, which might be fair enough but I'm not sure that the word initializer conveys all that (new to async-land) responsibility.
This is true but I don't know if it's really an issue; regardless of what the user does we're still creating a stream. I think initialiser is fine in this context though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
paging @dnadoba who usually has great instincts with naming...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're assuming inboundStreamIntializer
is the right name, which isn't necessarily the case (although it matters much less IMO because trailing closure syntax). Maybe it should also just be initializer
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO naming it just initializer
is a step back. We just had recent feedback in the forums that a users was confused about what that initializer does. So become more vague feels like a step in the wrong direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just had recent feedback in the forums that a users was confused about what that initializer does.
Can you share a link to this?
Neither inboundStreamIntializer
nor initializer
will tell you what an initialiser does. inboundStream
tells you what the initialiser applies to, without inboundStream
you assume from the context what it applies to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment was in the Swift Open Source Slack actually and not in the forums. This was the users feedback
update: i finally got an HTTP/2 request working, the piece i was missing was that you still need to add your application stream handler in NIOHTTP2Handler.StreamMultiplexer.createStreamChannel(_:), even if you already provided a callback when setting up the handlers with Channel.configureHTTP2Pipeline. which was very counterintuitive given how the docs are worded:
https://swiftinit.org/docs/swift-nio-http2/niohttp2/niohttp2handler.multiplexer
it gave the impression that if you provide the callback during outer setup then the multiplexer is “ready to go” and you can just return $0.eventLoop.createSucceededVoidFuture(). please update these docs 🙂
To be fair it is more about the documentation explaining the different of the two closures and why both are needed.
Personally, I think there is still value in having outbound in the method name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's absolutely about the docs and not about the naming. The linked docs do call out that it's an outbound stream which wasn't sufficient so I'm not sure keeping it in the name makes a difference. That said, this isn't a hill I'll die on!
docs/public-async-nio-apis.md
Outdated
public let inboundStream: NIOCore.NIOAsyncChannelInboundStream<Inbound> | ||
|
||
/// The writer for writing outbound messages. | ||
public let outboundWriter: NIOCore.NIOAsyncChannelOutboundWriter<Outbound> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about naming here: both "stream" and "writer" are in the type names. Would prefer inbound
and outbound
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not yet convinced. It feels a bit magical that users should know that inbound implies stream and outbound implies writer. Could be the other way around as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not difficult to discover though, both the type and the documentation are present to help users know what to do with them.
I have a pretty strong aversion to including type names in property names... and I don't think there are many places where you'd be happy with widgetsArray
as a name vs widgets
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm with George FWIW. The fact that the things which offer inbound and outbound functionality are different types shouldn't be a surprise to anyone, and they will need to check the types to see how to interact with them anyway.
docs/public-async-nio-apis.md
Outdated
public func configureAsyncHTTP2Pipeline<Output: Sendable>( | ||
mode: NIOHTTP2Handler.ParserMode, | ||
configuration: NIOHTTP2Handler.Configuration = .init(), | ||
position: ChannelPipeline.Position = .last, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We almost certainly have to drop it: semantically the only place we can do this is last. What does it mean to add your async channel handlers not last?
5408154
to
186c789
Compare
handlers which bridge the read and write side using the | ||
`NIOAsyncSequenceProducer` and the `NIOAsyncWriter`. | ||
|
||
Next up we had to look at the bootstraps. Here the import part is that the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Next up we had to look at the bootstraps. Here the import part is that the | |
Next we had to look at the bootstraps. Here the important part was recognizing that the |
# Motivation To ease reviewing of all the new APIs and to document some of the thought process behind them, I threw together a document that collects all of it. We can use this document to holistcally review the APIs now before removing the SPI.
f7a8a21
to
a49804e
Compare
Motivation
To ease reviewing of all the new APIs and to document some of the thought process behind them, I threw together a document that collects all of it.
We can use this document to holistcally review the APIs now before removing the SPI.