diff --git a/Sources/NIOCore/AsyncChannel/AsyncChannel.swift b/Sources/NIOCore/AsyncChannel/AsyncChannel.swift index 10354f0760..74fdd53dcb 100644 --- a/Sources/NIOCore/AsyncChannel/AsyncChannel.swift +++ b/Sources/NIOCore/AsyncChannel/AsyncChannel.swift @@ -301,15 +301,13 @@ public struct NIOAsyncChannel: Sendable { } } - do { - self._outbound.finish() - try await self.channel.close().get() - } catch { - if let error = error as? ChannelError, error == .alreadyClosed { - return result - } - throw error - } + self._outbound.finish() + // We ignore errors from close, since all we care about is that the channel has been closed + // at this point. + self.channel.close(promise: nil) + // `closeFuture` is never failed, so we can ignore the error + try? await self.channel.closeFuture.get() + return result } } diff --git a/Sources/NIOCore/Channel.swift b/Sources/NIOCore/Channel.swift index 8d0af1fec5..227efce5ce 100644 --- a/Sources/NIOCore/Channel.swift +++ b/Sources/NIOCore/Channel.swift @@ -107,6 +107,11 @@ public protocol Channel: AnyObject, ChannelOutboundInvoker, _NIOPreconcurrencySe var allocator: ByteBufferAllocator { get } /// The `closeFuture` will fire when the `Channel` has been closed. + /// + /// - Important: This future will never be failed, as it signals when the channel has been closed, and this action cannot fail. + /// If you are interested in any errors thrown during `close` to diagnose any unclean channel closures, you + /// should instead use the future returned from ``close(mode:file:line:)`` or pass a promise via + /// ``close(mode:promise:)``. var closeFuture: EventLoopFuture { get } /// The `ChannelPipeline` which handles all I/O events and requests associated with this `Channel`.