From c38b35835031096ce5f6e686d6cf03ecee0a3374 Mon Sep 17 00:00:00 2001 From: Sam Agarwal Date: Thu, 16 Jul 2026 17:37:55 -0400 Subject: [PATCH] Fix setRetryOptions merging initialInterval into congestionInitialInterval RpcRetryOptions.Builder.setRetryOptions merged every field from its own counterpart except congestionInitialInterval, which read o.getInitialInterval(). The source's congestionInitialInterval was therefore never read, and the value was overwritten by the regular initial interval. congestionInitialInterval is the backoff applied to RESOURCE_EXHAUSTED (used by GrpcSyncRetryer/GrpcAsyncRetryer via BackoffThrottler) and defaults to 10x the regular interval (1000ms vs 100ms). Merging collapsed that margin, so a client would retry an already-congested server far faster than intended - the opposite of what the setting exists for. Read o.getCongestionInitialInterval() and add a regression test asserting a user-set congestion interval survives setRetryOptions. --- .../serviceclient/RpcRetryOptions.java | 3 +- .../serviceclient/RpcRetryOptionsTest.java | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 temporal-serviceclient/src/test/java/io/temporal/serviceclient/RpcRetryOptionsTest.java diff --git a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/RpcRetryOptions.java b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/RpcRetryOptions.java index a105098f43..bddcca5a14 100644 --- a/temporal-serviceclient/src/main/java/io/temporal/serviceclient/RpcRetryOptions.java +++ b/temporal-serviceclient/src/main/java/io/temporal/serviceclient/RpcRetryOptions.java @@ -272,7 +272,8 @@ public Builder setRetryOptions(RpcRetryOptions o) { setInitialInterval( OptionsUtils.merge(initialInterval, o.getInitialInterval(), Duration.class)); setCongestionInitialInterval( - OptionsUtils.merge(congestionInitialInterval, o.getInitialInterval(), Duration.class)); + OptionsUtils.merge( + congestionInitialInterval, o.getCongestionInitialInterval(), Duration.class)); setExpiration(OptionsUtils.merge(expiration, o.getExpiration(), Duration.class)); setMaximumInterval( OptionsUtils.merge(maximumInterval, o.getMaximumInterval(), Duration.class)); diff --git a/temporal-serviceclient/src/test/java/io/temporal/serviceclient/RpcRetryOptionsTest.java b/temporal-serviceclient/src/test/java/io/temporal/serviceclient/RpcRetryOptionsTest.java new file mode 100644 index 0000000000..8b66a2ded3 --- /dev/null +++ b/temporal-serviceclient/src/test/java/io/temporal/serviceclient/RpcRetryOptionsTest.java @@ -0,0 +1,30 @@ +package io.temporal.serviceclient; + +import static org.junit.Assert.assertEquals; + +import java.time.Duration; +import org.junit.Test; + +public class RpcRetryOptionsTest { + + /** + * congestionInitialInterval is the backoff used for RESOURCE_EXHAUSTED and is deliberately set + * much higher than initialInterval. Builder.setRetryOptions must merge it from the source's + * congestionInitialInterval, not from its initialInterval, otherwise that margin is silently + * collapsed. + */ + @Test + public void setRetryOptionsMergesCongestionInitialInterval() { + RpcRetryOptions source = + RpcRetryOptions.newBuilder() + .setInitialInterval(Duration.ofMillis(200)) + .setCongestionInitialInterval(Duration.ofSeconds(7)) + .validateBuildWithDefaults(); + + RpcRetryOptions merged = + RpcRetryOptions.newBuilder().setRetryOptions(source).validateBuildWithDefaults(); + + assertEquals(Duration.ofMillis(200), merged.getInitialInterval()); + assertEquals(Duration.ofSeconds(7), merged.getCongestionInitialInterval()); + } +}