From e028d86bc9abe555e480e502fda4983dc50973a9 Mon Sep 17 00:00:00 2001 From: Alex Panchenko <440271+panchenko@users.noreply.github.com> Date: Thu, 28 Aug 2025 16:33:59 +0200 Subject: [PATCH 1/2] servlet: add extra 5s to AsyncContext timeout --- .../main/java/io/grpc/servlet/ServletAdapter.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java b/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java index 4bfe8949776..1706691a78c 100644 --- a/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java +++ b/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java @@ -128,10 +128,9 @@ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOEx } Long timeoutNanos = headers.get(TIMEOUT_KEY); - if (timeoutNanos == null) { - timeoutNanos = 0L; - } - asyncCtx.setTimeout(TimeUnit.NANOSECONDS.toMillis(timeoutNanos)); + asyncCtx.setTimeout(timeoutNanos != null + ? TimeUnit.NANOSECONDS.toMillis(timeoutNanos) + ASYNC_TIMEOUT_SAFETY_MARGIN + : 0); StatsTraceContext statsTraceCtx = StatsTraceContext.newServerContext(streamTracerFactories, method, headers); @@ -158,6 +157,11 @@ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOEx asyncCtx.addListener(new GrpcAsyncListener(stream, logId)); } + /** + * Deadlines are managed via Context, servlet async timeout is not supposed to happen. + */ + private static final long ASYNC_TIMEOUT_SAFETY_MARGIN = 5_000; + // This method must use Enumeration and its members, since that is the only way to read headers // from the servlet api. @SuppressWarnings("JdkObsolete") From 3e69193680959de557ca47c5c4fb375fca4ed594 Mon Sep 17 00:00:00 2001 From: Alex Panchenko <440271+panchenko@users.noreply.github.com> Date: Thu, 28 Aug 2025 17:00:39 +0200 Subject: [PATCH 2/2] fix unit test --- servlet/src/main/java/io/grpc/servlet/ServletAdapter.java | 4 +++- .../test/java/io/grpc/servlet/ServletServerBuilderTest.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java b/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java index 1706691a78c..d59888d2480 100644 --- a/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java +++ b/servlet/src/main/java/io/grpc/servlet/ServletAdapter.java @@ -22,6 +22,7 @@ import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINEST; +import com.google.common.annotations.VisibleForTesting; import com.google.common.io.BaseEncoding; import io.grpc.Attributes; import io.grpc.ExperimentalApi; @@ -160,7 +161,8 @@ public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOEx /** * Deadlines are managed via Context, servlet async timeout is not supposed to happen. */ - private static final long ASYNC_TIMEOUT_SAFETY_MARGIN = 5_000; + @VisibleForTesting + static final long ASYNC_TIMEOUT_SAFETY_MARGIN = 5_000; // This method must use Enumeration and its members, since that is the only way to read headers // from the servlet api. diff --git a/servlet/src/test/java/io/grpc/servlet/ServletServerBuilderTest.java b/servlet/src/test/java/io/grpc/servlet/ServletServerBuilderTest.java index d571cfd45d5..7a8c5b91f25 100644 --- a/servlet/src/test/java/io/grpc/servlet/ServletServerBuilderTest.java +++ b/servlet/src/test/java/io/grpc/servlet/ServletServerBuilderTest.java @@ -80,7 +80,7 @@ public void scheduledExecutorService() throws Exception { ServletAdapter servletAdapter = serverBuilder.buildServletAdapter(); servletAdapter.doPost(request, response); - verify(asyncContext).setTimeout(1); + verify(asyncContext).setTimeout(1 + ServletAdapter.ASYNC_TIMEOUT_SAFETY_MARGIN); // The following just verifies that scheduler is populated to the transport. // It doesn't matter what tasks (such as handshake timeout and request deadline) are actually