0.7.25
This commit is contained in:
@@ -44,10 +44,10 @@ impl HttpEndpointPool {
|
||||
"http endpoint pool requires at least one client".to_string(),
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
return Ok(Self {
|
||||
clients,
|
||||
next_index: std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0)),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Creates a pool from endpoint configurations.
|
||||
@@ -66,22 +66,22 @@ impl HttpEndpointPool {
|
||||
};
|
||||
clients.push(client);
|
||||
}
|
||||
Self::new(clients)
|
||||
return Self::new(clients);
|
||||
}
|
||||
|
||||
/// Creates a pool from the global configuration.
|
||||
pub fn from_config(config: &crate::KbConfig) -> Result<Self, crate::KbError> {
|
||||
Self::from_endpoint_configs(config.solana.http_endpoints.clone())
|
||||
return Self::from_endpoint_configs(config.solana.http_endpoints.clone());
|
||||
}
|
||||
|
||||
/// Returns the number of pooled clients.
|
||||
pub fn len(&self) -> usize {
|
||||
self.clients.len()
|
||||
return self.clients.len();
|
||||
}
|
||||
|
||||
/// Returns whether the pool is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.clients.is_empty()
|
||||
return self.clients.is_empty();
|
||||
}
|
||||
|
||||
/// Returns a live snapshot of pooled endpoints.
|
||||
@@ -94,7 +94,7 @@ impl HttpEndpointPool {
|
||||
crate::KbHttpEndpointStatus::Disabled => ("Disabled".to_string(), None),
|
||||
crate::KbHttpEndpointStatus::Paused { remaining_ms } => {
|
||||
("Paused".to_string(), Some(remaining_ms))
|
||||
}
|
||||
},
|
||||
};
|
||||
snapshots.push(KbHttpPoolClientSnapshot {
|
||||
endpoint_name: client.endpoint_name().to_string(),
|
||||
@@ -106,7 +106,7 @@ impl HttpEndpointPool {
|
||||
available_concurrency_slots: client.available_concurrency_slots(),
|
||||
});
|
||||
}
|
||||
snapshots
|
||||
return snapshots;
|
||||
}
|
||||
|
||||
/// Selects one client for a role and method.
|
||||
@@ -134,13 +134,13 @@ impl HttpEndpointPool {
|
||||
match status {
|
||||
crate::KbHttpEndpointStatus::Active => {
|
||||
active_indices.push(index);
|
||||
}
|
||||
},
|
||||
crate::KbHttpEndpointStatus::Paused { .. } => {
|
||||
paused_count += 1;
|
||||
}
|
||||
},
|
||||
crate::KbHttpEndpointStatus::Disabled => {
|
||||
disabled_count += 1;
|
||||
}
|
||||
},
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
@@ -150,9 +150,7 @@ impl HttpEndpointPool {
|
||||
required_role, method, paused_count, disabled_count, role_mismatch_count
|
||||
)));
|
||||
}
|
||||
let rotation_seed = self
|
||||
.next_index
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let rotation_seed = self.next_index.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
let active_len = active_indices.len();
|
||||
let mut offset = 0usize;
|
||||
while offset < active_len {
|
||||
@@ -164,7 +162,7 @@ impl HttpEndpointPool {
|
||||
offset += 1;
|
||||
}
|
||||
let fallback_index = active_indices[rotation_seed % active_len];
|
||||
Ok(self.clients[fallback_index].clone())
|
||||
return Ok(self.clients[fallback_index].clone());
|
||||
}
|
||||
|
||||
/// Executes one raw JSON-RPC request through the pool.
|
||||
@@ -174,14 +172,12 @@ impl HttpEndpointPool {
|
||||
method: std::string::String,
|
||||
params: std::vec::Vec<serde_json::Value>,
|
||||
) -> Result<serde_json::Value, crate::KbError> {
|
||||
let client_result = self
|
||||
.select_client_for_role_and_method(required_role, &method)
|
||||
.await;
|
||||
let client_result = self.select_client_for_role_and_method(required_role, &method).await;
|
||||
let client = match client_result {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
client.execute_json_rpc_result_raw(method, params).await
|
||||
return client.execute_json_rpc_result_raw(method, params).await;
|
||||
}
|
||||
|
||||
/// Executes one typed JSON-RPC request through the pool.
|
||||
@@ -194,28 +190,25 @@ impl HttpEndpointPool {
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
let client_result = self
|
||||
.select_client_for_role_and_method(required_role, &method)
|
||||
.await;
|
||||
let client_result = self.select_client_for_role_and_method(required_role, &method).await;
|
||||
let client = match client_result {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
client
|
||||
.execute_json_rpc_request_typed::<T>(method, params)
|
||||
.await
|
||||
return client.execute_json_rpc_request_typed::<T>(method, params).await;
|
||||
}
|
||||
/// Executes `getHealth` through the pool.
|
||||
pub async fn get_health_for_role(
|
||||
&self,
|
||||
required_role: &str,
|
||||
) -> Result<std::string::String, crate::KbError> {
|
||||
self.execute_json_rpc_request_typed_for_role::<std::string::String>(
|
||||
required_role,
|
||||
"getHealth".to_string(),
|
||||
std::vec::Vec::new(),
|
||||
)
|
||||
.await
|
||||
return self
|
||||
.execute_json_rpc_request_typed_for_role::<std::string::String>(
|
||||
required_role,
|
||||
"getHealth".to_string(),
|
||||
std::vec::Vec::new(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Executes `getSlot` through the pool.
|
||||
@@ -231,12 +224,13 @@ impl HttpEndpointPool {
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let params = kb_pool_build_optional_config_only_params(config_value);
|
||||
self.execute_json_rpc_request_typed_for_role::<u64>(
|
||||
required_role,
|
||||
"getSlot".to_string(),
|
||||
params,
|
||||
)
|
||||
.await
|
||||
return self
|
||||
.execute_json_rpc_request_typed_for_role::<u64>(
|
||||
required_role,
|
||||
"getSlot".to_string(),
|
||||
params,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Executes `sendTransaction` through the pool.
|
||||
@@ -254,12 +248,13 @@ impl HttpEndpointPool {
|
||||
};
|
||||
let params =
|
||||
kb_pool_build_first_string_optional_config_params(encoded_transaction, config_value);
|
||||
self.execute_json_rpc_request_typed_for_role::<std::string::String>(
|
||||
required_role,
|
||||
"sendTransaction".to_string(),
|
||||
params,
|
||||
)
|
||||
.await
|
||||
return self
|
||||
.execute_json_rpc_request_typed_for_role::<std::string::String>(
|
||||
required_role,
|
||||
"sendTransaction".to_string(),
|
||||
params,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Executes `getTransaction` through the pool and returns the raw result value.
|
||||
@@ -269,14 +264,29 @@ impl HttpEndpointPool {
|
||||
signature: std::string::String,
|
||||
config: std::option::Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value, crate::KbError> {
|
||||
let client_result = self
|
||||
.select_client_for_role_and_method(required_role, "getTransaction")
|
||||
.await;
|
||||
let client_result =
|
||||
self.select_client_for_role_and_method(required_role, "getTransaction").await;
|
||||
let client = match client_result {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
client.get_transaction_raw(signature, config).await
|
||||
return client.get_transaction_raw(signature, config).await;
|
||||
}
|
||||
|
||||
/// Executes `getAccountInfo` through the pool and returns the raw result value.
|
||||
pub async fn get_account_info_raw_for_role(
|
||||
&self,
|
||||
required_role: &str,
|
||||
address: std::string::String,
|
||||
config: std::option::Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value, crate::KbError> {
|
||||
let client_result =
|
||||
self.select_client_for_role_and_method(required_role, "getAccountInfo").await;
|
||||
let client = match client_result {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
return client.get_account_info_raw(address, config).await;
|
||||
}
|
||||
|
||||
/// Executes `getProgramAccounts` through the pool and returns the raw result value.
|
||||
@@ -293,7 +303,7 @@ impl HttpEndpointPool {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
client.get_program_accounts_raw(program_id, config).await
|
||||
return client.get_program_accounts_raw(program_id, config).await;
|
||||
}
|
||||
|
||||
/// Executes `getSignaturesForAddress` through the pool and returns the raw result value.
|
||||
@@ -310,7 +320,7 @@ impl HttpEndpointPool {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
client.get_signatures_for_address_raw(address, config).await
|
||||
return client.get_signatures_for_address_raw(address, config).await;
|
||||
}
|
||||
|
||||
/// Executes typed `getSignaturesForAddress` through the pool.
|
||||
@@ -330,7 +340,7 @@ impl HttpEndpointPool {
|
||||
Ok(client) => client,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
client.get_signatures_for_address(address, config).await
|
||||
return client.get_signatures_for_address(address, config).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +352,7 @@ fn kb_pool_build_optional_config_only_params(
|
||||
if let Some(config) = config {
|
||||
params.push(config);
|
||||
}
|
||||
params
|
||||
return params;
|
||||
}
|
||||
|
||||
fn kb_pool_build_first_string_optional_config_params(
|
||||
@@ -350,11 +360,10 @@ fn kb_pool_build_first_string_optional_config_params(
|
||||
config: std::option::Option<serde_json::Value>,
|
||||
) -> std::vec::Vec<serde_json::Value> {
|
||||
let mut params = vec![serde_json::Value::String(first)];
|
||||
|
||||
if let Some(config) = config {
|
||||
params.push(config);
|
||||
}
|
||||
params
|
||||
return params;
|
||||
}
|
||||
|
||||
fn kb_pool_serialize_optional_json_value<T>(
|
||||
@@ -368,14 +377,16 @@ where
|
||||
Some(value) => {
|
||||
let value_result = serde_json::to_value(value);
|
||||
match value_result {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(error) => Err(crate::KbError::Json(format!(
|
||||
"cannot serialize {}: {error}",
|
||||
label
|
||||
))),
|
||||
Ok(value) => return Ok(Some(value)),
|
||||
Err(error) => {
|
||||
return Err(crate::KbError::Json(format!(
|
||||
"cannot serialize {}: {error}",
|
||||
label
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
None => Ok(None),
|
||||
},
|
||||
None => return Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,11 +483,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
});
|
||||
Self {
|
||||
return Self {
|
||||
url: format!("http://{}", local_addr),
|
||||
shutdown_tx: Some(shutdown_tx),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async fn shutdown(mut self) {
|
||||
if let Some(shutdown_tx) = self.shutdown_tx.take() {
|
||||
let _ = shutdown_tx.send(());
|
||||
@@ -490,7 +502,7 @@ mod tests {
|
||||
url: std::string::String,
|
||||
roles: std::vec::Vec<std::string::String>,
|
||||
) -> crate::KbHttpEndpointConfig {
|
||||
crate::KbHttpEndpointConfig {
|
||||
return crate::KbHttpEndpointConfig {
|
||||
name: name.to_string(),
|
||||
enabled: true,
|
||||
provider: provider.to_string(),
|
||||
@@ -508,7 +520,7 @@ mod tests {
|
||||
max_idle_connections_per_host: 4,
|
||||
max_concurrent_requests_per_endpoint: 2,
|
||||
pause_after_http_429_ms: Some(1500),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -595,12 +607,8 @@ mod tests {
|
||||
.expect("pool creation must succeed");
|
||||
let snapshots = pool.snapshot().await;
|
||||
assert_eq!(snapshots.len(), 2);
|
||||
assert!(snapshots.iter().any(|snapshot| snapshot.status == "Active"));
|
||||
assert!(
|
||||
snapshots
|
||||
.iter()
|
||||
.any(|snapshot| snapshot.status == "Disabled")
|
||||
);
|
||||
assert!(snapshots.iter().any(|snapshot| return snapshot.status == "Active"));
|
||||
assert!(snapshots.iter().any(|snapshot| return snapshot.status == "Disabled"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -669,18 +677,16 @@ mod tests {
|
||||
client_a.disable().await;
|
||||
let pool =
|
||||
crate::HttpEndpointPool::new(vec![client_a]).expect("pool creation must succeed");
|
||||
let result = pool
|
||||
.select_client_for_role_and_method("http_queries", "getSlot")
|
||||
.await;
|
||||
let result = pool.select_client_for_role_and_method("http_queries", "getSlot").await;
|
||||
assert!(result.is_err());
|
||||
let error = result.expect_err("selection must fail");
|
||||
match error {
|
||||
crate::KbError::Http(message) => {
|
||||
assert!(message.contains("no active http endpoint available"));
|
||||
}
|
||||
},
|
||||
other => {
|
||||
panic!("unexpected error: {other:?}");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user