Skip to content

Commit 9f3ed41

Browse files
devondragonclaude
andcommitted
Add configurable HTTP timeouts for Cloudflare API calls
Introduces connection and read timeout configuration to prevent indefinite hangs when communicating with Cloudflare's Turnstile API. This improves resilience by ensuring failed or slow API calls fail fast rather than blocking indefinitely. Changes: - Added connectTimeout and readTimeout properties (default 5s and 10s) - Configured RestClient with JdkClientHttpRequestFactory for timeout support - Added timeout configuration to turnstile.properties - Added startup logging for configured timeout values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent cb05d9f commit 9f3ed41

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

src/main/java/com/digitalsanctuary/cf/turnstile/config/TurnstileConfigProperties.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ public class TurnstileConfigProperties {
5656
*/
5757
private String url;
5858

59+
/**
60+
* Connection timeout in seconds. Defaults to 5 seconds.
61+
*/
62+
private int connectTimeout = 5;
63+
64+
/**
65+
* Read timeout in seconds. Defaults to 10 seconds.
66+
*/
67+
private int readTimeout = 10;
68+
5969
/**
6070
* Configuration for metrics and monitoring.
6171
*/

src/main/java/com/digitalsanctuary/cf/turnstile/config/TurnstileServiceConfig.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package com.digitalsanctuary.cf.turnstile.config;
22

3+
import java.net.http.HttpClient;
4+
import java.time.Duration;
35
import java.util.Optional;
46
import org.springframework.beans.factory.ObjectProvider;
57
import org.springframework.beans.factory.annotation.Qualifier;
68
import org.springframework.context.annotation.Bean;
79
import org.springframework.context.annotation.Configuration;
810
import org.springframework.http.HttpHeaders;
911
import org.springframework.http.MediaType;
12+
import org.springframework.http.client.JdkClientHttpRequestFactory;
1013
import org.springframework.web.client.RestClient;
1114
import com.digitalsanctuary.cf.turnstile.service.TurnstileValidationService;
1215
import io.micrometer.core.instrument.MeterRegistry;
@@ -45,8 +48,24 @@ public TurnstileValidationService turnstileValidationService(@Qualifier("turnsti
4548
@Bean(name = "turnstileRestClient")
4649
public RestClient turnstileRestClient() {
4750
log.info("Creating Turnstile REST client with endpoint: {}", properties.getUrl());
48-
return RestClient.builder().baseUrl(properties.getUrl()).defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
49-
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).build();
51+
log.info("Turnstile REST client timeouts - connect: {}s, read: {}s",
52+
properties.getConnectTimeout(), properties.getReadTimeout());
53+
54+
// Configure HttpClient with timeouts
55+
HttpClient httpClient = HttpClient.newBuilder()
56+
.connectTimeout(Duration.ofSeconds(properties.getConnectTimeout()))
57+
.build();
58+
59+
// Create request factory with the configured HttpClient
60+
JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient);
61+
requestFactory.setReadTimeout(Duration.ofSeconds(properties.getReadTimeout()));
62+
63+
return RestClient.builder()
64+
.baseUrl(properties.getUrl())
65+
.requestFactory(requestFactory)
66+
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
67+
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
68+
.build();
5069
}
5170

5271
}

src/main/resources/config/turnstile.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ ds.cf.turnstile.sitekey=
44
ds.cf.turnstile.secret=
55
ds.cf.turnstile.url=https://challenges.cloudflare.com/turnstile/v0/siteverify
66

7+
# Timeout configuration (in seconds)
8+
ds.cf.turnstile.connect-timeout=5
9+
ds.cf.turnstile.read-timeout=10
10+
711
# Configuration for TurnstileCaptchaFilter component (for use with Spring Security Form Login, etc...)
812
ds.cf.turnstile.login.submissionPath=/login
913
ds.cf.turnstile.login.redirectUrl=/login?error=captcha

0 commit comments

Comments
 (0)