Add a default timeout to all BeaconNodeHttpClient requests (#7400)

Add a default request timeout to all `BeaconNodeHttpClient` requests to ensure that no HTTP request can hang indefinitely.
This commit is contained in:
Jimmy Chen
2025-05-08 12:08:32 +10:00
committed by GitHub
parent 0f13029c7d
commit 8dc3d23af0
2 changed files with 27 additions and 16 deletions

View File

@@ -144,6 +144,7 @@ pub struct Timeouts {
pub get_debug_beacon_states: Duration, pub get_debug_beacon_states: Duration,
pub get_deposit_snapshot: Duration, pub get_deposit_snapshot: Duration,
pub get_validator_block: Duration, pub get_validator_block: Duration,
pub default: Duration,
} }
impl Timeouts { impl Timeouts {
@@ -161,6 +162,7 @@ impl Timeouts {
get_debug_beacon_states: timeout, get_debug_beacon_states: timeout,
get_deposit_snapshot: timeout, get_deposit_snapshot: timeout,
get_validator_block: timeout, get_validator_block: timeout,
default: timeout,
} }
} }
} }
@@ -235,7 +237,9 @@ impl BeaconNodeHttpClient {
url: U, url: U,
builder: impl FnOnce(RequestBuilder) -> RequestBuilder, builder: impl FnOnce(RequestBuilder) -> RequestBuilder,
) -> Result<Response, Error> { ) -> Result<Response, Error> {
let response = builder(self.client.get(url)).send().await?; let response = builder(self.client.get(url).timeout(self.timeouts.default))
.send()
.await?;
ok_or_error(response).await ok_or_error(response).await
} }
@@ -398,11 +402,10 @@ impl BeaconNodeHttpClient {
body: &T, body: &T,
timeout: Option<Duration>, timeout: Option<Duration>,
) -> Result<Response, Error> { ) -> Result<Response, Error> {
let mut builder = self.client.post(url); let builder = self
if let Some(timeout) = timeout { .client
builder = builder.timeout(timeout); .post(url)
} .timeout(timeout.unwrap_or(self.timeouts.default));
let response = builder.json(body).send().await?; let response = builder.json(body).send().await?;
ok_or_error(response).await ok_or_error(response).await
} }
@@ -415,10 +418,10 @@ impl BeaconNodeHttpClient {
timeout: Option<Duration>, timeout: Option<Duration>,
fork: ForkName, fork: ForkName,
) -> Result<Response, Error> { ) -> Result<Response, Error> {
let mut builder = self.client.post(url); let builder = self
if let Some(timeout) = timeout { .client
builder = builder.timeout(timeout); .post(url)
} .timeout(timeout.unwrap_or(self.timeouts.default));
let response = builder let response = builder
.header(CONSENSUS_VERSION_HEADER, fork.to_string()) .header(CONSENSUS_VERSION_HEADER, fork.to_string())
.json(body) .json(body)
@@ -433,7 +436,7 @@ impl BeaconNodeHttpClient {
url: U, url: U,
body: &T, body: &T,
) -> Result<Response, Error> { ) -> Result<Response, Error> {
let builder = self.client.post(url); let builder = self.client.post(url).timeout(self.timeouts.default);
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert( headers.insert(
@@ -452,10 +455,10 @@ impl BeaconNodeHttpClient {
timeout: Option<Duration>, timeout: Option<Duration>,
fork: ForkName, fork: ForkName,
) -> Result<Response, Error> { ) -> Result<Response, Error> {
let mut builder = self.client.post(url); let builder = self
if let Some(timeout) = timeout { .client
builder = builder.timeout(timeout); .post(url)
} .timeout(timeout.unwrap_or(self.timeouts.default));
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert( headers.insert(
CONSENSUS_VERSION_HEADER, CONSENSUS_VERSION_HEADER,
@@ -1868,7 +1871,13 @@ impl BeaconNodeHttpClient {
.push("node") .push("node")
.push("health"); .push("health");
let status = self.client.get(path).send().await?.status(); let status = self
.client
.get(path)
.timeout(self.timeouts.default)
.send()
.await?
.status();
if status == StatusCode::OK || status == StatusCode::PARTIAL_CONTENT { if status == StatusCode::OK || status == StatusCode::PARTIAL_CONTENT {
Ok(status) Ok(status)
} else { } else {

View File

@@ -68,6 +68,7 @@ const HTTP_GET_BEACON_BLOCK_SSZ_TIMEOUT_QUOTIENT: u32 = 4;
const HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT: u32 = 4; const HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT: u32 = 4;
const HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT: u32 = 4; const HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT: u32 = 4;
const HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT: u32 = 4; const HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT: u32 = 4;
const HTTP_DEFAULT_TIMEOUT_QUOTIENT: u32 = 4;
const DOPPELGANGER_SERVICE_NAME: &str = "doppelganger"; const DOPPELGANGER_SERVICE_NAME: &str = "doppelganger";
@@ -307,6 +308,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
get_debug_beacon_states: slot_duration / HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT, get_debug_beacon_states: slot_duration / HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT,
get_deposit_snapshot: slot_duration / HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT, get_deposit_snapshot: slot_duration / HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT,
get_validator_block: slot_duration / HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT, get_validator_block: slot_duration / HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT,
default: slot_duration / HTTP_DEFAULT_TIMEOUT_QUOTIENT,
} }
} else { } else {
Timeouts::set_all(slot_duration.saturating_mul(config.long_timeouts_multiplier)) Timeouts::set_all(slot_duration.saturating_mul(config.long_timeouts_multiplier))