Skip to content

Commit d73d862

Browse files
authored
Wait for closeFuture instead of close promise in NIOAsyncChannel's executeThenClose (#3032)
After the changes introduced in apple/swift-nio-http2#487, we need to make a small change in the implementation of `NIOAsyncChannel` to wait on the `closeFuture` instead of on `close`'s promise in the `executeThenClose` implementation. ### Motivation: `executeThenClose` shouldn't fail from errors arising from closing the channel - at this point, the user of the channel cannot really do anything, and since the channel has been closed, we should not fail since resources have been cleaned up anyways. ### Modifications: This PR changes the implementation of `NIOAsyncChannel` to wait on the `closeFuture` instead of on `close`'s promise in the `executeThenClose` implementation. It also updates the docs for `closeFuture` to better explain when it will be succeeded and why it won't ever be failed. ### Result: `executeThenClose` won't throw errors upon closing.
1 parent 6008911 commit d73d862

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

Sources/NIOCore/AsyncChannel/AsyncChannel.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,15 +301,25 @@ public struct NIOAsyncChannel<Inbound: Sendable, Outbound: Sendable>: Sendable {
301301
}
302302
}
303303

304+
self._outbound.finish()
305+
// We ignore errors from close, since all we care about is that the channel has been closed
306+
// at this point.
307+
self.channel.close(promise: nil)
308+
// `closeFuture` should never be failed, so we could ignore the error. However, do an
309+
// assertionFailure to guide bad Channel implementations that are incorrectly failing this
310+
// future to stop failing it.
304311
do {
305-
self._outbound.finish()
306-
try await self.channel.close().get()
312+
try await self.channel.closeFuture.get()
307313
} catch {
308-
if let error = error as? ChannelError, error == .alreadyClosed {
309-
return result
310-
}
311-
throw error
314+
assertionFailure(
315+
"""
316+
The channel's closeFuture should never be failed, but it was failed with error: \(error).
317+
This is an error in the channel's implementation.
318+
Refer to `Channel/closeFuture`'s documentation for more information.
319+
"""
320+
)
312321
}
322+
313323
return result
314324
}
315325
}

Sources/NIOCore/Channel.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ public protocol Channel: AnyObject, ChannelOutboundInvoker, _NIOPreconcurrencySe
107107
var allocator: ByteBufferAllocator { get }
108108

109109
/// The `closeFuture` will fire when the `Channel` has been closed.
110+
///
111+
/// - Important: This future should never be failed: it signals when the channel has been closed, and this action should not fail,
112+
/// regardless of whether the close happenned cleanly or not.
113+
/// If you are interested in any errors thrown during `close` to diagnose any unclean channel closures, you
114+
/// should instead use the future returned from ``ChannelOutboundInvoker/close(mode:file:line:)-7hlgf``
115+
/// or pass a promise via ``ChannelOutboundInvoker/close(mode:promise:)``.
110116
var closeFuture: EventLoopFuture<Void> { get }
111117

112118
/// The `ChannelPipeline` which handles all I/O events and requests associated with this `Channel`.

0 commit comments

Comments
 (0)