The external client/connection interface expects that to complete
full request/response cycles. However, at await points the stack
could simply be dropped, meaning the connection is left in an
inconsistent state. One relatively likely scenario is that a
transaction might be dropped while waiting for a response from the
server. For example, this might happen if the connection was
initiated by a HTTP request which was canceled/aborted.
There are different failure modes which can result from similar
scenarios depending on during what await point the future was
dropped. Since it's relatively difficult to protect against
these scenarios and some of them might manifest in indirect ways
(for example, a deserialization error might happen because the
incoming response was for a different kind of request), this PR
takes the approach of tracking in the connection whether we're
(supposedly) at a point where the connection is ready to send
another request. If transact() is called while the connection is
not in such a state, the connection will transparently attempt
to reconnect to clean up any erroneous state.