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

Add onRequest() hook for propagating request from downstream #34388

Conversation

chenggangpro
Copy link
Contributor

@chenggangpro chenggangpro commented Feb 8, 2025

Try to fix #34178
After reproducing and debugging the issue, I found the onRequest() hook is missing. After the fix, the MultipartParser is functioning properly, and the upload hang issue has not occurred again. I tested this locally.

Signed-off-by: Gang Cheng <[email protected]>
@sdeleuze
Copy link
Contributor

I have the same analysis than @bclozel in #34178 (comment), I think this change, while probably fixing the issue, is going to over-request. We need to explore and understand what triggers this more in detail before crafting a fix. As a consequence, I will close this PR unmerged in favor of #34178.

@sdeleuze sdeleuze closed this Feb 19, 2025
@sdeleuze sdeleuze added status: duplicate A duplicate of another issue in: web Issues in web modules (web, webmvc, webflux, websocket) and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Feb 19, 2025
@sdeleuze sdeleuze reopened this Feb 20, 2025
@sdeleuze sdeleuze added type: bug A general bug and removed status: duplicate A duplicate of another issue labels Feb 20, 2025
@sdeleuze sdeleuze added this to the 6.2.4 milestone Feb 20, 2025
@sdeleuze
Copy link
Contributor

Reopening this PR based on #34178 (comment).

@sdeleuze sdeleuze closed this in 4606337 Feb 21, 2025
@sdeleuze sdeleuze reopened this Feb 21, 2025
@sdeleuze
Copy link
Contributor

sdeleuze commented Feb 21, 2025

Reopening to refine in order to prevent over-requesting based on a discussion with @chemicL.

@sdeleuze
Copy link
Contributor

sdeleuze commented Feb 25, 2025

@bclozel @chemicL @rstoyanchev I tried to add a private final AtomicBoolean waitingForRequest = new AtomicBoolean(); field to MultipartParser and changed

private void requestBuffer() {
		if (upstream() != null &&
				!this.sink.isCancelled() &&
				this.sink.requestedFromDownstream() > 0 &&
				this.requestOutstanding.compareAndSet(false, true)) {
			request(1);
		}
	}

To:

private void requestBuffer() {
		if (upstream() != null && !this.sink.isCancelled() && this.requestOutstanding.compareAndSet(false, true)) {
			if (this.sink.requestedFromDownstream() > 0 || this.waitingForRequest.compareAndSet(true, false)) {
				request(1);
			}
			else {
				System.out.println("Waiting for request");
				this.waitingForRequest.set(true);
			}
		}
	}

After 20-30 tries, I saw the Waiting for request message printed but this version that tries to prevent over-requested does not fix the hanging issue anymore unlike what is currently committed with 4606337.

I am wondering if there is really over-requesting, especially with the requestOutstanding field and related conditional requesting. Any guidance on how I could check if we are really over-requesting with the new implementation?

@sdeleuze sdeleuze added the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Feb 25, 2025
@chemicL
Copy link
Member

chemicL commented Feb 25, 2025

I think the above conditions won't match in case of resumption.

The problematic scenario seems to be the following:

  1. Downstream issued request and is now at requestedFromDownstream = 1, requestOutstanding is flipped to true
  2. Upstream delivers the requested value satisfying the demand (requestOutstanding = false, requestedFromDownstream = 0)
  3. requestBuffer resulting from upstream's logic to re-request internally (notice now there can be 2 calls - the other potentially following from the onNext in the downstream)
  4. requestOutstanding flipped to true, but requestedFromDownstream = 0, fail
  5. downstream requests, but can't flip requestOutstanding to true, since it already is true and no request is made -> stalemate.

Usually the downstream requests a higher number so the initial value is not 1 and progress can be made for some time.

I think the requestOutstanding flag present in the existing implementation is enough to protect against over-requesting. I'm sorry if my concerns have caused unnecessary confusion.

@sdeleuze
Copy link
Contributor

No problem @chemicL, thanks a lot for taking the time to share your detailed feedback, I will close the PR and keep what is committed then.

@sdeleuze sdeleuze closed this Feb 25, 2025
@sdeleuze sdeleuze removed the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: bug A general bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebFlux MultipartParser Blocks When Uploading Large Files, Causing Uploads to Occasionally Hang
4 participants