Skip to content

MLE-30245 Add configurable HTTP read/write timeouts to DatabaseClientBuilder#1948

Open
jonmille wants to merge 1 commit into
developfrom
MLE-30245
Open

MLE-30245 Add configurable HTTP read/write timeouts to DatabaseClientBuilder#1948
jonmille wants to merge 1 commit into
developfrom
MLE-30245

Conversation

@jonmille

@jonmille jonmille commented Jun 23, 2026

Copy link
Copy Markdown

Problem

Previously, all HTTP connections made by the Java client used OkHttp's default behavior of no read or write timeout. Long-running requests could therefore block indefinitely, exhausting thread pools in multi-tenant or production applications with no mechanism to recover without a JVM restart.

Solution

Two new fluent methods on DatabaseClientBuilder allow callers to set read and write timeouts with any TimeUnit:

  • withReadTimeout(long value, TimeUnit unit)
  • withWriteTimeout(long value, TimeUnit unit)

Both methods validate that the value is non-negative and that the unit is non-null, then store the timeout in milliseconds. A value of zero preserves the existing no-timeout behavior. The timeouts flow through to OkHttp only when positive, leaving the existing default unchanged.

For Spring-based applications, the same timeouts can be configured via property sources using:

  • marklogic.client.readTimeoutMillis
  • marklogic.client.writeTimeoutMillis

Changes

File Description
DatabaseClientBuilder Added withReadTimeout and withWriteTimeout methods with input validation and @since 8.2.0 Javadoc
DatabaseClientFactory Added readTimeoutMillis / writeTimeoutMillis fields and accessors to Bean; added 8-arg newClient overload; 6-arg overload now delegates to 8-arg with zeros
DatabaseClientPropertySource Added handlers for readTimeoutMillis and writeTimeoutMillis properties; newClient() passes timeout values through the 8-arg overload to preserve the global handle registry
OkHttpServices.ConnectionConfig Added readTimeoutMillis and writeTimeoutMillis to the record
OkHttpServices.connect() Applies read/write timeouts to the OkHttp client builder when the configured value is positive
OkHttpTimeoutTest New test class verifying: timeouts are applied to the OkHttp client, defaults remain zero, and a read timeout fires a SocketTimeoutException against a stalling MockWebServer
DatabaseClientBuilderTest Added tests for default zero timeouts and round-trip timeout configuration
DatabaseClientPropertySourceTest Added tests for Long, String, and Integer input types flowing through the property source

Testing

  • All new and existing unit tests pass
  • OkHttpTimeoutTest.readTimeoutFiresWhenServerStalls uses a 100 ms client timeout against a 5-second server delay to verify that a SocketTimeoutException is actually thrown, not just that a timeout value is stored
  • Property source tests cover Long, String, and Integer value types
  • Builder tests verify that zero is the default and that configured values are stored correctly

Backward Compatibility

No breaking changes. All existing callers that do not configure timeouts continue to use OkHttp's no-timeout default (value of zero). The new 8-arg newClient overload is additive; the existing 6-arg overload delegates to it with zeros.

Jira Link: https://progresssoftware.atlassian.net/browse/MLE-30245

Expose withReadTimeout() and withWriteTimeout() on DatabaseClientBuilder so callers can configure per-client OkHttp read and write timeouts without relying on global defaults.
@jonmille jonmille requested a review from BillFarber as a code owner June 23, 2026 19:25
Copilot AI review requested due to automatic review settings June 23, 2026 19:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds configurable OkHttp read/write timeouts to the MarkLogic Java client, exposing them via DatabaseClientBuilder, Spring-style property sources, and DatabaseClientFactory, and wiring the values into OkHttpServices while preserving the existing default “no timeout” behavior.

Changes:

  • Added fluent builder methods and bean properties for readTimeoutMillis/writeTimeoutMillis (default 0).
  • Plumbed timeouts through DatabaseClientFactory and DatabaseClientPropertySource into OkHttpServices, applying them on the OkHttp client builder when > 0.
  • Added/updated unit tests verifying defaults, configuration round-tripping, property parsing, and an end-to-end read-timeout firing scenario via MockWebServer.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientBuilder.java Adds withReadTimeout/withWriteTimeout builder APIs that store values in millis.
marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java Adds new timeout-aware newClient overload and timeout fields/accessors on Bean.
marklogic-client-api/src/main/java/com/marklogic/client/impl/DatabaseClientPropertySource.java Adds property handlers for timeout millis and passes them through to the timeout-aware newClient overload.
marklogic-client-api/src/main/java/com/marklogic/client/impl/OkHttpServices.java Extends ConnectionConfig with read/write timeouts and applies them to the OkHttp client builder.
marklogic-client-api/src/test/java/com/marklogic/client/test/DatabaseClientBuilderTest.java Adds assertions for default (0) timeouts and configured millis values.
marklogic-client-api/src/test/java/com/marklogic/client/impl/DatabaseClientPropertySourceTest.java Adds tests for timeout properties from Long/String/Integer sources.
marklogic-client-api/src/test/java/com/marklogic/client/impl/okhttp/OkHttpTimeoutTest.java New tests validating wiring to OkHttp and a behavioral read-timeout firing case.

Comment on lines 153 to 156
public record ConnectionConfig(String host, int port, String basePath, String database,
SecurityContext securityContext, List<OkHttpClientConfigurator> clientConfigurators) {
SecurityContext securityContext, List<OkHttpClientConfigurator> clientConfigurators,
long readTimeoutMillis, long writeTimeoutMillis) {
}
Comment on lines +224 to +229
if (config.readTimeoutMillis() > 0) {
clientBuilder.readTimeout(config.readTimeoutMillis(), TimeUnit.MILLISECONDS);
}
if (config.writeTimeoutMillis() > 0) {
clientBuilder.writeTimeout(config.writeTimeoutMillis(), TimeUnit.MILLISECONDS);
}
Comment on lines +43 to +47
/**
* Verifies that a configured read timeout actually fires when the server stalls before sending
* any response. This is an end-to-end behavioral test: if the timeout were not wired to the
* OkHttpClient, the call would block indefinitely rather than throwing a SocketTimeoutException.
*/

@rjrudin rjrudin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend against doing this. A user can already configure these timeouts via DatabaseClientFactory.addConfigurator(new OkHttpClientConfigurator(...)).

So the problem identified by MLE-30245 - that the default timeouts of zero can possibly be exploited - can already be solved.

The ticket would thus need to justify the addition to the public API for the above solution. I don't think that justification exists. The main reason is that the OkHttp Builder has dozens of methods for configuring an OkHttp connection; the read and write timeouts are just two of them. There are two other timeouts as well - the connect timeout and the call timeout.

Adding these probably-very-rarely-used timeouts to public APIs creates a pattern that doesn't scale well - i.e. just how many OkHttp-specific parameters are we going to add to the public API, when a user already has a way of configuring these parameters?

@rjdew-progress

Copy link
Copy Markdown

@rjrudin It looks like configuring it with a OkHttpClientConfigurator for the DatabaseClientFactory sets the values globally.

How does the scenario work when you have separate clients that you want to have different timeout values?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants