feat: add configurable retry mechanism for API requests
parent
92c16fdc3d
commit
5f1b30772b
|
@ -3,6 +3,7 @@ output_path = "output_keys.txt"
|
|||
backup_path = "backup_keys.txt"
|
||||
api_host = "https://generativelanguage.googleapis.com/"
|
||||
timeout_sec = 20
|
||||
max_retries = 2
|
||||
concurrency = 30
|
||||
proxy = "http://username:password@host:port"
|
||||
enable_multiplexing = true
|
||||
|
|
|
@ -39,6 +39,10 @@ struct Cli {
|
|||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
concurrency: Option<usize>,
|
||||
|
||||
#[arg(short = 'r', long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
max_retries: Option<usize>,
|
||||
|
||||
#[arg(short = 'x', long)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
proxy: Option<Url>,
|
||||
|
@ -66,6 +70,10 @@ pub struct KeyCheckerConfig {
|
|||
#[serde(default)]
|
||||
pub timeout_sec: u64,
|
||||
|
||||
// Maximum number of retries for failed requests.
|
||||
#[serde(default)]
|
||||
pub max_retries: usize,
|
||||
|
||||
// Maximum number of concurrent requests.
|
||||
#[serde(default)]
|
||||
pub concurrency: usize,
|
||||
|
@ -154,6 +162,7 @@ static DEFAULT_CONFIG: LazyLock<KeyCheckerConfig> = LazyLock::new(|| KeyCheckerC
|
|||
api_host: Url::parse("https://generativelanguage.googleapis.com/").unwrap(),
|
||||
timeout_sec: 15,
|
||||
concurrency: 50,
|
||||
max_retries: 2,
|
||||
proxy: None,
|
||||
enable_multiplexing: true,
|
||||
log_level: "info".to_string(),
|
||||
|
|
|
@ -4,7 +4,7 @@ use tokio::time::Duration;
|
|||
use tracing::{debug, error, info, warn};
|
||||
use url::Url;
|
||||
|
||||
use crate::config::TEST_MESSAGE_BODY;
|
||||
use crate::config::{KeyCheckerConfig, TEST_MESSAGE_BODY};
|
||||
use crate::error::ValidatorError;
|
||||
use crate::types::GeminiKey;
|
||||
|
||||
|
@ -12,18 +12,24 @@ pub async fn validate_key(
|
|||
client: Client,
|
||||
api_endpoint: impl IntoUrl,
|
||||
api_key: GeminiKey,
|
||||
config: KeyCheckerConfig,
|
||||
) -> Result<GeminiKey, ValidatorError> {
|
||||
let api_endpoint = api_endpoint.into_url()?;
|
||||
|
||||
match send_test_request(client, &api_endpoint, api_key.clone()).await {
|
||||
match send_test_request(client, &api_endpoint, api_key.clone(), config.max_retries).await {
|
||||
Ok(_) => {
|
||||
info!("SUCCESS - {}... - Valid key found", &api_key.as_ref()[..10]);
|
||||
Ok(api_key)
|
||||
}
|
||||
Err(e) => {
|
||||
match e.status() {
|
||||
Some(StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN | StatusCode::TOO_MANY_REQUESTS) => {
|
||||
warn!("INVALID - {}... - {}", &api_key.as_ref()[..10], ValidatorError::KeyInvalid);
|
||||
Err(e) => match e.status() {
|
||||
Some(
|
||||
StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN | StatusCode::TOO_MANY_REQUESTS,
|
||||
) => {
|
||||
warn!(
|
||||
"INVALID - {}... - {}",
|
||||
&api_key.as_ref()[..10],
|
||||
ValidatorError::KeyInvalid
|
||||
);
|
||||
Err(ValidatorError::KeyInvalid)
|
||||
}
|
||||
_ => {
|
||||
|
@ -31,8 +37,7 @@ pub async fn validate_key(
|
|||
error!("ERROR- {}... - {}", &api_key.as_ref()[..10], req_error);
|
||||
Err(req_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,11 +45,12 @@ async fn send_test_request(
|
|||
client: Client,
|
||||
api_endpoint: &Url,
|
||||
key: GeminiKey,
|
||||
max_retries: usize,
|
||||
) -> Result<reqwest::Response, reqwest::Error> {
|
||||
let retry_policy = ExponentialBuilder::default()
|
||||
.with_max_times(3)
|
||||
.with_min_delay(Duration::from_secs(3))
|
||||
.with_max_delay(Duration::from_secs(5));
|
||||
.with_max_times(max_retries)
|
||||
.with_min_delay(Duration::from_secs(1))
|
||||
.with_max_delay(Duration::from_secs(2));
|
||||
|
||||
(async || {
|
||||
let response = client
|
||||
|
|
|
@ -48,7 +48,14 @@ impl ValidationService {
|
|||
|
||||
// Create stream to validate keys concurrently
|
||||
let valid_keys_stream = stream
|
||||
.map(|key| validate_key(self.client.clone(), self.full_url.clone(), key))
|
||||
.map(|key| {
|
||||
validate_key(
|
||||
self.client.clone(),
|
||||
self.full_url.clone(),
|
||||
key,
|
||||
self.config.clone(),
|
||||
)
|
||||
})
|
||||
.buffer_unordered(self.config.concurrency)
|
||||
.filter_map(|result| async { result.ok() });
|
||||
pin_mut!(valid_keys_stream);
|
||||
|
@ -72,7 +79,6 @@ impl ValidationService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn start_validation() -> Result<(), ValidatorError> {
|
||||
let config = KeyCheckerConfig::load_config()?;
|
||||
|
||||
|
|
Loading…
Reference in New Issue