Skip to content

Conversation

@becomeStar
Copy link
Contributor

@becomeStar becomeStar commented Nov 22, 2025

Background

In the gRPC servlet transport with Tomcat 10 Embedded,
we observed occasional flaky tests in grpc-servlet-jakarta:tomcat10Test.
The issue is related to a race condition where the OutputBuffer is prematurely recycled during asynchronous writes.

Changes

Reference: spring-projects/spring-boot#36763 (comment)

This PR explicitly calls .setDiscardFacades(false) on the Tomcat 10 Embedded Connector.
The intention is to prevent outputBuffer reuse, so that the above race condition does not occur during tests.

Purpose

  • Reduce the likelihood of flaky tests in grpc-servlet-jakarta:tomcat10Test
  • Apply the method suggested in the referenced Spring Boot discussion

Note

This change aligns Tomcat 10 Embedded behavior with Tomcat 9 (where RECYCLE_FACADES defaults to false), and is known to prevent premature OutputBuffer recycling during async writes.
Based on the investigation and prior reports (e.g., Spring Boot discussion),
this is currently the correct and safe configuration for servlet-based asynchronous responses in Tomcat 10.

Fixes #12524

@becomeStar becomeStar force-pushed the servlet/fix-flaky-recycle branch from 67c9aa0 to 120a197 Compare November 25, 2025 13:18
@becomeStar
Copy link
Contributor Author

I re-read the contribution guidelines and realized I had incorrectly included two lines of code formatting along with the core logic change, which violates the "Don't fix code style" rule. I have reverted the formatting changes, so this PR now only contains the intended one line of core logic change: .setDiscardFacades(false);.

I believe this single line resolves the issue described in #12524, but I would like to confirm if the maintainers also consider this approach appropriate.

Set discardFacades=false in Tomcat 10 Embedded to avoid premature
OutputBuffer recycling. This prevents flaky tests in gRPC servlet
transport by ensuring facades are not discarded too early.

Fixes grpc#12524
@becomeStar becomeStar force-pushed the servlet/fix-flaky-recycle branch from 120a197 to 7272a28 Compare November 25, 2025 14:12
@ejona86
Copy link
Member

ejona86 commented Nov 27, 2025

The issue is related to a race condition where the OutputBuffer is prematurely recycled during asynchronous writes.

Why are they prematurely recycled? That seems to be the problem. It is either a bug in Tomcat or in gRPC. The linked issue says:

You are relying upon the request still be usable after its handling has completed which may not work reliably.

So it seems we need to fix our code to stop using the request when it is no longer valid. Or at least that should be the initial goal. Maybe we can't because of some reason, but then we'd want to understand why.

@ejona86
Copy link
Member

ejona86 commented Nov 27, 2025

I would accept this change as a "make the tests stop flaking," but then we'd want to create a new issue to track the bug involved here.

@becomeStar
Copy link
Contributor Author

@ejona86

Thank you for the insightful feedback. You are absolutely right.

I agree that disabling facade recycling is a workaround to stabilize the tests. We should investigate whether gRPC is accessing the request/response objects (specifically the underlying OutputBuffer) after their lifecycle has ended.

As you suggested, I will:

  1. Keep this PR focused on fixing the test flakiness.
  2. Open a new issue to track and investigate the root cause of the premature recycling due to the lifecycle mismatch between Tomcat's object recycling and gRPC's asynchronous usage.

I'll create the issue shortly and reference it here.

@becomeStar
Copy link
Contributor Author

becomeStar commented Nov 27, 2025

I've created the tracking issue: #12540.
I'll investigate the root cause of the recycling behavior there.

Copy link
Member

@ejona86 ejona86 left a comment

Choose a reason for hiding this comment

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

One small change, then seems it could go in.

.setAsyncSupported(true);
ctx.addServletMappingDecoded("/*", "TomcatTransportTest");
tomcatServer.getConnector().addUpgradeProtocol(new Http2Protocol());
tomcatServer.getConnector().setDiscardFacades(false);
Copy link
Member

Choose a reason for hiding this comment

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

Let's add a comment saying this is a workaround and have a link to the issue you created.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ejona86

Added the workaround comment with the issue link. Thanks for the review.
I'll continue investigating the root cause in #12540."

@ejona86 ejona86 added the kokoro:run Add this label to a PR to tell Kokoro the code is safe and tests can be run label Dec 1, 2025
@grpc-kokoro grpc-kokoro removed the kokoro:run Add this label to a PR to tell Kokoro the code is safe and tests can be run label Dec 1, 2025
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Dec 2, 2025

CLA Signed

The committers listed above are authorized under a signed CLA.

@becomeStar becomeStar force-pushed the servlet/fix-flaky-recycle branch from cde3d48 to 7272a28 Compare December 2, 2025 01:23
@ejona86 ejona86 added the kokoro:run Add this label to a PR to tell Kokoro the code is safe and tests can be run label Dec 2, 2025
@grpc-kokoro grpc-kokoro removed the kokoro:run Add this label to a PR to tell Kokoro the code is safe and tests can be run label Dec 2, 2025
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.

TomcatTransportTest.clientChecksInboundMetadataSize_header is flaky

3 participants