[
https://issues.apache.org/jira/browse/CAMEL-24784?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18116267#comment-18116267
]
Andrea Cosentino commented on CAMEL-24784:
------------------------------------------
Fixed via #26524 (squash-merged to main, 4.23.0):
https://github.com/apache/camel/pull/26524 (commit 0076168a5cd4).
_Claude Code on behalf of Andrea Cosentino (@oscerd)_
> camel-opa - the REST decision call has no timeout and builds a new HttpClient
> per message
> -----------------------------------------------------------------------------------------
>
> Key: CAMEL-24784
> URL: https://issues.apache.org/jira/browse/CAMEL-24784
> Project: Camel
> Issue Type: Bug
> Reporter: Andrea Cosentino
> Assignee: Andrea Cosentino
> Priority: Major
> Fix For: 4.23.0
>
>
> h2. Problem
> In {{evaluationMode=rest}} - the default - the decision call cannot time out,
> and allocates a fresh HTTP client for every message.
> {{camel-opa}} builds its client with {{new OPAClient(serverUrl)}} / {{new
> OPAClient(serverUrl, headers)}}. Neither passes an {{HTTPClient}}, so the SDK
> falls back to {{SpeakeasyHTTPClient}}, whose entire implementation is:
> {code:java}
> public HttpResponse<InputStream> send(HttpRequest request) throws ... {
> HttpClient client = HttpClient.newHttpClient();
> ...
> return client.send(request, HttpResponse.BodyHandlers.ofInputStream());
> }
> {code}
> Verified against the {{com.styra:opa:2.1.1}} bytecode.
> h3. 1. No timeout
> {{HttpClient.newHttpClient()}} applies no connect timeout, and nothing in the
> SDK sets {{HttpRequest.Builder.timeout}} (checked across every class in the
> artifact). Both JDK defaults are "wait indefinitely".
> So an OPA server that accepts the connection and then does not answer parks
> the calling thread for ever. For a component whose contract is *fail closed*,
> this is the worst available failure mode: it never reaches a decision, so it
> never denies - it simply stops. {{failOpen}} does not help either, because
> that branch is downstream of the call that never returns.
> A *refused* connection fails fast, so this only appears against a host that
> accepts and stalls - precisely the case that does not reproduce locally.
> {{evaluationMode=wasm}} does not have this problem: CAMEL-24741 gave it a
> bounded {{borrowTimeout}}. The gap is on the default mode.
> h3. 2. A new HttpClient per message
> {{send()}} constructs an {{HttpClient}} per request. On the Java 17 baseline
> {{HttpClient}} is not {{AutoCloseable}}, so each one holds its selector
> thread and executor until it is collected. {{OpaProducerHealthCheck}} already
> shares a single client for exactly this reason, and the probe fires once per
> health poll - while this fires once per *message* through an
> {{OpaSecurityPolicy}}.
> h2. Fix
> {{OPAClient}} has a constructor {{camel-opa}} never uses: {{OPAClient(String
> serverUrl, HTTPClient)}}. A small camel-owned {{HTTPClient}} holding one
> shared {{java.net.http.HttpClient}} (built with a connect timeout) and
> rebuilding each request with a read timeout closes both.
> {{HttpRequest.newBuilder(HttpRequest, BiPredicate)}} makes the rebuild
> possible without reconstructing the request by hand - confirmed on 17.
> New options {{connectionTimeout}} (default 10s) and {{requestTimeout}}
> (default 30s). A borrow that times out is an evaluation failure, not a deny,
> so it fails closed - or proceeds under {{failOpen}} - like any other.
> h2. Scope
> {{main}} only. {{camel-opa}} is new and unreleased in 4.23.0, so nothing
> released changes and no advisory is warranted.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)