Skip to content

Ensure HTTP/2 flow control to work at the stream level #6266

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

ikhoon
Copy link
Contributor

@ikhoon ikhoon commented Jun 4, 2025

Motivation:

Since InboundTrafficController operates at the TCP level, it isn't aligned with HTTP/2 flow control. As a result, a stream may receive more than its stream window size allows and interfering with other streams from receiving data.

Related: #6253

Modifications:

  • Integrated InboundTrafficController with HTTP/2 Http2LocalFlowController
    • Invokes Http2LocalFlowController.consumeBytes() when steam data is consumed to send a WINDOW_UPDATE frame.
  • Introduced {ServerBuilder,ClientFactoryBuilder}.http2StreamWindowUpdateRatio to customize the threshold to send WINDOW_UPDATE frames.
  • Fixed client.Http2ResponseDecoder and server.Http2RequestDecoder to defer reporting the consumed data length.
    • The length is not reported via InboundTrafficController when the data is consumed in userland.

Result:

Motivation:

Since `InboundTrafficController` operates at the TCP level, it isn't
aligned with HTTP/2 flow control. As a result, a stream may receive more
than its stream window size allows and interfering with other streams
from recieving data.

Related: line#6253

Modifications:

- Integrated `InboundTrafficConroller` with HTTP/2
  `Http2LocalFlowController`
  - Invokes `Http2LocalFlowController.consumeBytes()` when steam data is
    consumed to send a `WINDOW_UPDATE` frame.
- Introduced `{ServerBuilder,ClientFactoryBuilder}.http2StreamWindowUpdateRatio`
  to customize the threshold to send WINDOW_UPDATE frames.
- Fixed `client.Http2ResponseDecoder` and `serer.Http2RequestDecoder`
  to defer reporting the consumed data length.
  - The length is not reported via `InboundTrafficController` when
    the data is consumed in userland.

Result:

- Fixed a bug where HTTP/2 flow control did not work properly, and
  stream-level windowing was ignored.
- Closes line#6253

Co-authored-by: Yizhou Feng <[email protected]>
@ikhoon ikhoon added this to the 1.33.0 milestone Jun 4, 2025
@ikhoon ikhoon added the defect label Jun 4, 2025
Copy link

codecov bot commented Jun 5, 2025

Codecov Report

Attention: Patch coverage is 91.11111% with 8 lines in your changes missing coverage. Please review.

Project coverage is 74.57%. Comparing base (8150425) to head (114f227).
Report is 104 commits behind head on main.

Files with missing lines Patch % Lines
...eria/internal/common/InboundTrafficController.java 78.57% 3 Missing and 3 partials ⚠️
...c/main/java/com/linecorp/armeria/common/Flags.java 75.00% 1 Missing ⚠️
...p/armeria/internal/client/DecodedHttpResponse.java 83.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6266      +/-   ##
============================================
+ Coverage     74.46%   74.57%   +0.11%     
- Complexity    22234    22476     +242     
============================================
  Files          1963     1985      +22     
  Lines         82437    83079     +642     
  Branches      10764    10787      +23     
============================================
+ Hits          61385    61957     +572     
- Misses        15918    15967      +49     
- Partials       5134     5155      +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ikhoon ikhoon marked this pull request as ready for review June 5, 2025 09:06
Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

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

Understood the main change is http2 flow control is updated when the request/response corresponding to the stream is consumed instead of immediately at onDataRead

@jrhee17
Copy link
Contributor

jrhee17 commented Jun 10, 2025

Note: I understood that if users are not interested in the server request or client response (fire-and-forget pattern), then the window frame won't be sent.
ref: https://github.com/jrhee17/armeria/tree/poc/fire-and-forget

I think most users won't be using this pattern since, but something to keep in mind in case someone asks about this behavior after applying this patch.

Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

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

👍 👍 👍

@ikhoon
Copy link
Contributor Author

ikhoon commented Jun 20, 2025

if users are not interested in the server request or client response (fire-and-forget pattern)

From what I understand, Armeria requires users to consume all HttpResponses to avoid memory leaks.

@yzfeng2020
Copy link
Contributor

hi @trustin could you review it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Potential bug: InboundTrafficController applies back-pressure at connection level only, ignoring per-stream windows
4 participants