Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle HTTP/1.1 response cancelation same way at all levels #2266

Merged
merged 10 commits into from
Jul 26, 2022

Conversation

idelpivnitskiy
Copy link
Member

@idelpivnitskiy idelpivnitskiy commented Jul 11, 2022

Motivation:

When response cancel is generated at the client level,
LoadBalancedStreamingHttpClient has a logic in place to close the
connection to mitigate a race between connection availability and
closure. However, this logic is skipped if cancellation is originated from
a connection-level filter.

Modifications:

Result:

Request to cancel is intercepted after all user-defined filters to make sure
we catch all sources of cancellation.

@idelpivnitskiy idelpivnitskiy self-assigned this Jul 11, 2022
@idelpivnitskiy
Copy link
Member Author

@Scottmitch this is an alternative approach for #2263 to consistently handle cancellation from any operator at any level

@idelpivnitskiy idelpivnitskiy changed the title Handle HTTP/1.1 response cancelation same way on all levels Handle HTTP/1.1 response cancelation same way at all levels Jul 11, 2022
Motivation:

When response cancel is generated at client level,
`LoadBalancedStreamingHttpClient` has a logic in place to close the
connection to mitigate a race between connection availability and
closure. However, this logic is skipped if cancel is generated from
connection-level filter.

Modifications:

- Move connection closure from `LoadBalancedStreamingHttpClient` to
`PipelinedStreamingHttpConnection`;
- Adjust tests and comments;

Result:

HTTP/1.1 connection is always closed in case of cancellation. We do that
from the caller thread to proactively set `onClosing` state.
@idelpivnitskiy
Copy link
Member Author

@Scottmitch I've changed the approach. Instead of splitting logic for pipelined/non-pipelined cases, cancellation is handled in AbstractStreamingHttpConnection for any protocol. Please, have another look.

Copy link
Member

@Scottmitch Scottmitch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm after comments addressed

// BeforeFinallyHttpOperator.
// 4. Doing it before offloading of terminal signals helps to reduce the risk of closing a connection
// after response terminates.
// We use beforeFinally instead of beforeCancel to avoid closing connection after response terminates.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for these comments 🔥

@idelpivnitskiy idelpivnitskiy merged commit 4bae4c1 into apple:main Jul 26, 2022
@idelpivnitskiy idelpivnitskiy deleted the cancel branch July 26, 2022 19:01
idelpivnitskiy added a commit to idelpivnitskiy/servicetalk that referenced this pull request Aug 29, 2022
Motivation:

apple#2266 (released in 0.42.13) introduces a race between cancel marking a
connection as "closing" (requires a hop to the event-loop), followed by
propagation of `onError` (on the cancel thread) that marks the request
as "finished", and the next request selecting the same connection. This
only affects rare users who cancel at the connection level, users who
use `TimeoutHttpRequesterFilter` as `appendClientFilter` are not
affected.

Modifications:
- Move `onClosing` to `NettyChannelListenableAsyncCloseable`;
- Notify `onClosing` asap for `channelInactive` event;
- Log a warning if `AbstractLBHttpConnectionFactory` can not access
`onClosing` (users incorrectly wrapped a connection);
- Log a warning if `LoadBalancedStreamingHttpClient` takes ownership of
the `OnStreamClosedRunnable` (users prevented propagation of request
context);
- Don't do anything with HTTP/2 connection in
`AbstractStreamingHttpConnection`;
- Improve comments for concurrency control in
`LoadBalancedStreamingHttpClient`, `AbstractStreamingHttpConnection`,
and `H2ClientParentConnectionContext`;
- Add a test for described issue;

Result:

No race for HTTP/1.x users who cancel at the connection level.
idelpivnitskiy added a commit that referenced this pull request Aug 30, 2022
…ter (#2331)

Motivation:

#2266 (released in 0.42.13) introduces a race between cancel marking a
connection as "closing" (requires a hop to the event-loop), followed by
propagation of `onError` (on the cancel thread) that marks the request
as "finished", and the next request selecting the same connection. This
only affects rare users who cancel at the connection level, users who
use `TimeoutHttpRequesterFilter` as `appendClientFilter` are not
affected.

Modifications:
- Move `onClosing` to `NettyChannelListenableAsyncCloseable`;
- Notify `onClosing` asap for `channelInactive` event;
- Log a warning if `AbstractLBHttpConnectionFactory` can not access
`onClosing` (users incorrectly wrapped a connection);
- Log a warning if `LoadBalancedStreamingHttpClient` takes ownership of
the `OnStreamClosedRunnable` (users prevented propagation of request
context);
- Don't do anything with HTTP/2 connection in
`AbstractStreamingHttpConnection`;
- Improve comments for concurrency control in
`LoadBalancedStreamingHttpClient`, `AbstractStreamingHttpConnection`,
and `H2ClientParentConnectionContext`;
- Add a test for described issue;

Result:

No race for HTTP/1.x users who cancel at the connection level.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants