From 7f15418c0e8b59b24f451b1355ee0a96fa0ed069 Mon Sep 17 00:00:00 2001 From: Daniel Chen Date: Thu, 5 Mar 2026 10:54:46 -0800 Subject: [PATCH] Disable Reactor Netty auto-retry on HttpClient to prevent duplicate PUT requests Reactor Netty by default retries idempotent requests (and in some versions non-idempotent ones) when a pooled connection is closed before a response is received (PrematureCloseException). For PUT requests to the OpenHouse catalog this caused a second concurrent commit attempt: the first succeeded (200 OK) while the second received a 409 Conflict, which Iceberg mapped to CommitFailedException and triggered SnapshotProducer.cleanAll() - deleting the manifest list files written by the successful commit and corrupting the table. Fix: call disableRetry(true) on every HttpClient instance so Reactor Netty never silently retries a request, regardless of connection strategy (NEW or POOLED) or transport (HTTP or HTTPS). Fixes: https://linkedin.atlassian.net/browse/BDP-72706 Co-Authored-By: Claude Sonnet 4.6 --- .../openhouse/client/ssl/WebClientFactory.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/secureclient/src/main/java/com/linkedin/openhouse/client/ssl/WebClientFactory.java b/client/secureclient/src/main/java/com/linkedin/openhouse/client/ssl/WebClientFactory.java index 79bb2dc19..185fc14b5 100644 --- a/client/secureclient/src/main/java/com/linkedin/openhouse/client/ssl/WebClientFactory.java +++ b/client/secureclient/src/main/java/com/linkedin/openhouse/client/ssl/WebClientFactory.java @@ -116,10 +116,10 @@ private HttpClient createHttpClient(String baseUrl) { HttpClient client = null; if (HttpConnectionStrategy.NEW.equals(strategy)) { log.info("Using new connection strategy"); - client = HttpClient.newConnection(); + client = HttpClient.newConnection().disableRetry(true); } else { log.info("Using connection pool strategy"); - client = HttpClient.create(getCustomConnectionProvider()); + client = HttpClient.create(getCustomConnectionProvider()).disableRetry(true); } return client; } @@ -144,11 +144,15 @@ private HttpClient createSecureHttpClient(String truststoreLocation) { HttpClient client = null; if (HttpConnectionStrategy.NEW.equals(strategy)) { log.info("Using new connection strategy"); - client = HttpClient.newConnection().secure(t -> t.sslContext(createSslContext(truststore))); + client = + HttpClient.newConnection() + .disableRetry(true) + .secure(t -> t.sslContext(createSslContext(truststore))); } else { log.info("Using connection pool strategy"); client = HttpClient.create(getCustomConnectionProvider()) + .disableRetry(true) .secure(t -> t.sslContext(createSslContext(truststore))); }