`RedisConnection.isConnected` state is inaccurate when `channel.isActive` is false
While looking into building off of channel.isActive
for determining the value of RedisConnection.isConnected
, it was discovered that RedisConnection
doesn't properly handle unexpected closures of its channel
.
This is going to require a re-visit of the RedisConnection.ConnectionState
holistically - as there are improper assumptions made that the RedisConnection
is the sole control point of its Channel
.
[Notes from the SwiftNIO team]:
code is here: https://github.com/apple/swift-nio/blob/master/Sources/NIO/BaseSocketChannel.swift#L437-L465
closePromise
will be succeeded as the last thingorder is
- write fails
- remaining bytes in the socket will be read out
- channel gets deregistered
- underlying socket gets closed (fd released)
- internal state gets set to 'closed' (this will make the
isActive
thing turn false)- all outstanding writes (including the write that failed in step 1) get failed with write error received in step 1
channelInactive
gets sent through the pipeline- pipeline gets torn down
handlerRemoved
invoked everywhere- close promise gets fulfilled (ie.
closeFuture
is succeeded)all the steps can be found in
BaseSocketChannel.writeToSocket
andBaseSocketChannel.close0
so what's possible is that
isActive == false
butcloseFuture
not fulfilled yet (but will be very shortly)impossible is that
closeFuture
is fulfilled butisActive == true
if the socket is actively closed from the other side (ie. other side sends a FIN or RST), the flow is pretty similar. The error will just not come from a failed write but it'll be "connection reset by peer" or
ChannelError.eof
.If the channel support half-closure, then nothing much happens on FIN as the
Channel
is still active until our end also closes.