hank9999 commited on
Commit ·
7cd244e
1
Parent(s): 1d958fc
fix: 添加刷新锁避免多请求竞态问题
Browse files- src/kiro/token_manager.rs +37 -10
src/kiro/token_manager.rs
CHANGED
|
@@ -6,6 +6,7 @@
|
|
| 6 |
use anyhow::bail;
|
| 7 |
use chrono::{DateTime, Duration, Utc};
|
| 8 |
use parking_lot::Mutex;
|
|
|
|
| 9 |
|
| 10 |
use crate::http_client::{build_client, ProxyConfig};
|
| 11 |
use crate::kiro::machine_id;
|
|
@@ -382,6 +383,8 @@ pub struct MultiTokenManager {
|
|
| 382 |
entries: Mutex<Vec<CredentialEntry>>,
|
| 383 |
/// 当前活动凭据索引
|
| 384 |
current_index: Mutex<usize>,
|
|
|
|
|
|
|
| 385 |
}
|
| 386 |
|
| 387 |
/// 每个凭据最大 API 调用失败次数
|
|
@@ -431,6 +434,7 @@ impl MultiTokenManager {
|
|
| 431 |
proxy,
|
| 432 |
entries: Mutex::new(entries),
|
| 433 |
current_index: Mutex::new(0),
|
|
|
|
| 434 |
})
|
| 435 |
}
|
| 436 |
|
|
@@ -522,6 +526,8 @@ impl MultiTokenManager {
|
|
| 522 |
|
| 523 |
/// 尝试使用指定凭据获取有效 Token
|
| 524 |
///
|
|
|
|
|
|
|
| 525 |
/// # Arguments
|
| 526 |
/// * `index` - 凭据索引,用于更新正确的条目
|
| 527 |
/// * `credentials` - 凭据信息
|
|
@@ -530,19 +536,40 @@ impl MultiTokenManager {
|
|
| 530 |
index: usize,
|
| 531 |
credentials: &KiroCredentials,
|
| 532 |
) -> anyhow::Result<CallContext> {
|
| 533 |
-
|
|
|
|
| 534 |
|
| 535 |
-
|
| 536 |
-
|
|
|
|
| 537 |
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
|
|
|
|
|
|
| 541 |
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 546 |
|
| 547 |
let token = creds
|
| 548 |
.access_token
|
|
|
|
| 6 |
use anyhow::bail;
|
| 7 |
use chrono::{DateTime, Duration, Utc};
|
| 8 |
use parking_lot::Mutex;
|
| 9 |
+
use tokio::sync::Mutex as TokioMutex;
|
| 10 |
|
| 11 |
use crate::http_client::{build_client, ProxyConfig};
|
| 12 |
use crate::kiro::machine_id;
|
|
|
|
| 383 |
entries: Mutex<Vec<CredentialEntry>>,
|
| 384 |
/// 当前活动凭据索引
|
| 385 |
current_index: Mutex<usize>,
|
| 386 |
+
/// Token 刷新锁,确保同一时间只有一个刷新操作
|
| 387 |
+
refresh_lock: TokioMutex<()>,
|
| 388 |
}
|
| 389 |
|
| 390 |
/// 每个凭据最大 API 调用失败次数
|
|
|
|
| 434 |
proxy,
|
| 435 |
entries: Mutex::new(entries),
|
| 436 |
current_index: Mutex::new(0),
|
| 437 |
+
refresh_lock: TokioMutex::new(()),
|
| 438 |
})
|
| 439 |
}
|
| 440 |
|
|
|
|
| 526 |
|
| 527 |
/// 尝试使用指定凭据获取有效 Token
|
| 528 |
///
|
| 529 |
+
/// 使用双重检查锁定模式,确保同一时间只有一个刷新操作
|
| 530 |
+
///
|
| 531 |
/// # Arguments
|
| 532 |
/// * `index` - 凭据索引,用于更新正确的条目
|
| 533 |
/// * `credentials` - 凭据信息
|
|
|
|
| 536 |
index: usize,
|
| 537 |
credentials: &KiroCredentials,
|
| 538 |
) -> anyhow::Result<CallContext> {
|
| 539 |
+
// 第一次检查(无锁):快速判断是否需要刷新
|
| 540 |
+
let needs_refresh = is_token_expired(credentials) || is_token_expiring_soon(credentials);
|
| 541 |
|
| 542 |
+
let creds = if needs_refresh {
|
| 543 |
+
// 获取刷新锁,确保同一时间只有一个刷新操作
|
| 544 |
+
let _guard = self.refresh_lock.lock().await;
|
| 545 |
|
| 546 |
+
// 第二次检查:获取锁后重新读取凭据,因为其他请求可能已经完成刷新
|
| 547 |
+
let current_creds = {
|
| 548 |
+
let entries = self.entries.lock();
|
| 549 |
+
entries[index].credentials.clone()
|
| 550 |
+
};
|
| 551 |
|
| 552 |
+
if is_token_expired(¤t_creds) || is_token_expiring_soon(¤t_creds) {
|
| 553 |
+
// 确实需要刷新
|
| 554 |
+
let new_creds =
|
| 555 |
+
refresh_token(¤t_creds, &self.config, self.proxy.as_ref()).await?;
|
| 556 |
+
|
| 557 |
+
if is_token_expired(&new_creds) {
|
| 558 |
+
anyhow::bail!("刷新后的 Token 仍然无效或已过期");
|
| 559 |
+
}
|
| 560 |
+
|
| 561 |
+
// 更新凭据
|
| 562 |
+
let mut entries = self.entries.lock();
|
| 563 |
+
entries[index].credentials = new_creds.clone();
|
| 564 |
+
new_creds
|
| 565 |
+
} else {
|
| 566 |
+
// 其他请求已经完成刷新,直接使用新凭据
|
| 567 |
+
tracing::debug!("Token 已被其他请求刷新,跳过刷新");
|
| 568 |
+
current_creds
|
| 569 |
+
}
|
| 570 |
+
} else {
|
| 571 |
+
credentials.clone()
|
| 572 |
+
};
|
| 573 |
|
| 574 |
let token = creds
|
| 575 |
.access_token
|