http: add onComplete to AsyncClient::StreamCallbacks#7752
http: add onComplete to AsyncClient::StreamCallbacks#7752mattklein123 merged 16 commits intoenvoyproxy:masterfrom
Conversation
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
|
To expand on this, receiving If AsyncClient and friends are used from asymmetric code paths (sending stuff is somewhere separate from receiving stuff), it's not currently possible to infer when a stream is actually closed. Even in the case of bidirectional usage, since local and remote closure states are private, this bookkeeping must otherwise be replicated by anything that ties resources to stream lifecycle. |
|
In the original PR I stated, "This isn't required for AsyncRequest, since a request is a complete entity and the local stream will be closed as soon as it is sent." This is technically incorrect, since a remote could in theory return a response with |
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
mattklein123
left a comment
There was a problem hiding this comment.
Thanks this makes sense to me. Please check CI.
/wait
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
|
Thanks for the feedback so far everyone. Will make updates. (Also still stepping through one failing test.) |
Signed-off-by: Jose Nino <jnino@lyft.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
|
(ready for review) |
mattklein123
left a comment
There was a problem hiding this comment.
Thanks for working on this. This seems like a nice improvement. Some questions.
/wait-any
|
|
||
| void AsyncStreamImpl::closeLocal(bool end_stream) { | ||
| ASSERT(!(local_closed_ && end_stream)); | ||
| // Due to the fact that send calls can synchronously result in stream closure, it's possible for |
There was a problem hiding this comment.
I don't think I follow how this is happening. What's the callstack when we get called after being already closed?
There was a problem hiding this comment.
I'm inferring from tests, but I believe this can happen when the connection pool fails to provide a connection, and surfaces this via a locally-created 503 response.
There was a problem hiding this comment.
But how does that cause closeLocal() to get called twice?
|
|
||
| void AsyncStreamImpl::closeRemote(bool end_stream) { | ||
| remote_closed_ |= end_stream; | ||
| // Due to the fact that callbacks can synchronously result in stream closure, it's possible for |
There was a problem hiding this comment.
Again a bit hazy on how this happens. Can you provide more info?
There was a problem hiding this comment.
In this case, it's possible when a callback synchronously calls stream->reset. There's also a unit test that covers this.
There was a problem hiding this comment.
But if closes only happen in non-reset cases, why are we calling closeRemote() in the case of reset?
/wait-any
There was a problem hiding this comment.
Let's assume the case covered by the unit test.
We're in encodeHeaders:
stream_callbacks.onHeaders is called and synchronously resets the stream. reset calls resetStream which calls cleanup:
envoy/source/common/http/async_client_impl.cc
Line 190 in ef543d8
cleanup sets local and remote to be closed:
envoy/source/common/http/async_client_impl.cc
Line 180 in ef543d8
the callback finishes executing, but we're still in encodeHeaders, which looks to see if goes ahead and calls end_stream is true, and if it is,closeRemote:
This is largely existing behavior, which this PR preserves, except for the added guards to prevent "extra" closures/resets.
There was a problem hiding this comment.
OK I see. That was my confusion that we are using local_closed_ and remote_closed_ also in the case of reset. IMO this is kind of confusing, so if you want to somehow split this logic out I would go for that. If not, can you potentially make the comments in these cases a lot more robust for the next reader to come along? I think that would be good enough for me. Thank's for explaining all of this.
/wait
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
| } | ||
|
|
||
| void AsyncStreamImpl::closeLocal(bool end_stream) { | ||
| // TODO(goaway): This assert maybe merits reconsideration. It seems to be saying that we shouldn't |
Description: Add onComplete callback for asymmetric cases where end_stream may not be bidirectionally observable.
Risk Level: Medium
Testing: Updated unit tests
Co-authored-by: Jose Ulises Nino Rivera jnino@lyft.com
Signed-off-by: Mike Schore mike.schore@gmail.com