SCA-5930 Fix intermittent UA UPDATE "Read timed out" by disabling stale connection reuse#127
Merged
Merged
Conversation
…le connection reuse WssServiceClientImpl reused persistent keep-alive connections across requests with no stale-connection check and no idle/TTL eviction. A pooled connection silently dropped by an upstream load balancer / proxy / firewall (half-open) was reused for the large UPDATE POST issued after the minutes-long resolution phase; the request was written into a dead socket, no response arrived, and the read blocked for the full wss.connectionTimeoutMinutes (default 60 min) before the built-in retry recovered on a fresh connection in seconds. Disable HTTP connection reuse (NoConnectionReuseStrategy) on every client-creation path (default constructor, ignore-certificate constructor, and both setProxy builder paths) so each request uses a fresh connection and a stale/half-open socket can never be reused. No timeout semantics changed, so legitimately slow large updates are unaffected; the only cost is one extra connection setup per request, negligible for the agent's request volume. Reported via TKA-10393 (IBM ibmets, Cloud Software Group / Citrix SaaS-US). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
Estimated code review effort🎯 2 (Simple) | ⏱️ ~5 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
MuhammadAEws
approved these changes
Jun 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the intermittent
Failed to send request to WhiteSource server: Unexpected error. Response data is: Read timed outthat hangs the Unified Agent's firstSending Updaterequest for the full connection timeout (default 60 minutes) before the built-in retry recovers on a fresh connection in seconds.Jira: SCA-5930 · Customer evidence: TKA-10393 (IBM
ibmets, Cloud Software Group / Citrix SaaS-US — both strategic).Root cause
WssServiceClientImplbuilds its HTTP client withnew DefaultHttpClient()and reuses persistent (keep-alive) connections across every call (orgFlags → checkPolicies → UPDATE → getRequestState), with no stale-connection check and no idle/TTL eviction.When a pooled connection has been silently dropped by an upstream load balancer / proxy / firewall (half-open — no FIN/RST reaches the client), the next request — the large UPDATE POST, issued after the minutes-long dependency-resolution phase during which the connection sat idle — is written into a dead socket. No response ever arrives, so the socket read blocks for the entire
wss.connectionTimeoutMinutes(default 60). The automatic retry opens a new connection and the identical payload succeeds in 2–10 s.This is consistent across all three captured cases:
The stack trace confirms the client is blocked in
receiveResponseHeaderwith the request already sent. It is not a backend-performance issue — the backend processes the same payload in seconds, the failed request never reaches the server (no API_CALL, no CTX), and because the UA exitsSUCCESS(0)after the retry, the failure is invisible to server telemetry.Fix
Disable HTTP connection reuse via
NoConnectionReuseStrategyon every client-creation path so each request uses a fresh connection and a stale/half-open socket can never be reused:new DefaultHttpClient())setProxy()builder paths (reached viafindDefaultProxy())No timeout semantics are changed, so legitimately slow large updates are unaffected. The only cost is one extra connection setup (TLS handshake, ~tens of ms) per request — negligible for the agent's handful of requests per scan.
Why not just raise
wss.connectionTimeoutMinutes?The retry already succeeds in seconds, so 60 min is ample; a larger value only makes the failed attempt hang longer. The correct fix is to never reuse the dead connection in the first place.
Testing
mvn -pl wss-agent-client -am compile→ BUILD SUCCESSwss-agent-clientunit tests pass (pluswss-agent-api,wss-agent-utils).wss-agent-hash-calculatormodule, caused by local git CRLF→LF normalization of test fixtures — not touched by and cannot be affected by this change.Rollout
This artifact (
wss-agent-api-client) is consumed by the Unified Agent as a pinned dependency. After release, bumpagent.api.versionin theunified-agentpom.xml(currently2.9.9.100) to the new version and rebuild the Fat JAR.Follow-up (separate, not in this PR)
In
setProxy()the proxy clients are rebuilt aftersetConnectionTimeout()runs, so proxied clients currently receive no socket timeout at all. Best fixed by moving timeouts to a per-requestRequestConfig(works for all client types).🤖 Generated with Claude Code
Summary by CodeRabbit