hank9999 commited on
Commit
7cd244e
·
1 Parent(s): 1d958fc

fix: 添加刷新锁避免多请求竞态问题

Browse files
Files changed (1) hide show
  1. 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
- let mut creds = credentials.clone();
 
534
 
535
- if is_token_expired(&creds) || is_token_expiring_soon(&creds) {
536
- creds = refresh_token(&creds, &self.config, self.proxy.as_ref()).await?;
 
537
 
538
- if is_token_expired(&creds) {
539
- anyhow::bail!("刷新后的 Token 仍然无效或已过期");
540
- }
 
 
541
 
542
- // 使用传入的 index 更新凭据,避免竞态条件
543
- let mut entries = self.entries.lock();
544
- entries[index].credentials = creds.clone();
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(&current_creds) || is_token_expiring_soon(&current_creds) {
553
+ // 确实需要刷新
554
+ let new_creds =
555
+ refresh_token(&current_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