message: Token reloading with RwLock
diff: @@ -14,7 +14,7 @@ use jsonpath_lib::select as jsonpath_select;
  use secrecy::{ExposeSecret, SecretString};
  use serde::{Deserialize, Serialize};
  use thiserror::Error;
  -use tokio::sync::Mutex;
  +use tokio::sync::{Mutex, RwLock};
  use tower::{filter::AsyncPredicate, BoxError};
  use crate::config::{AuthInfo, AuthProviderConfig, ExecConfig};
  @@ -116,10 +116,12 @@ impl TokenFile {
  Utc::now() + Duration::seconds(10) > self.expires_at
  }
  + /// Get the cached token. Returns `None` if it's expiring.
  fn cached_token(&self) -> Option<&str> {
  (!self.is_expiring()).then(|| self.token.expose_secret().as_ref())
  }
  + /// Get a token. Reloads from file if the cached token is expiring.
  fn token(&mut self) -> &str {
  if self.is_expiring() {
  // > If reload from file fails, the last-read token should be used to avoid breaking
  @@ -148,7 +150,7 @@ impl TokenFile {
  #[derive(Debug, Clone)]
  pub enum RefreshableToken {
  Exec(Arc<Mutex<(SecretString, DateTime<Utc>, AuthInfo)>>),
  - File(Arc<Mutex<TokenFile>>),
  + File(Arc<RwLock<TokenFile>>),
  #[cfg(feature = "oauth")]
  GcpOauth(Arc<Mutex<oauth::Gcp>>),
  }
  @@ -206,12 +208,15 @@ impl RefreshableToken {
  }
  RefreshableToken::File(token_file) => {
  - let mut locked = token_file.lock().await;
  - if let Some(token) = locked.cached_token() {
  - bearer_header(token)
  - } else {
  - bearer_header(locked.token())
  + let guard = token_file.read().await;
  + if let Some(header) = guard.cached_token().map(bearer_header) {
  + return header;
  }
  + // Drop the read guard before a write lock attempt to prevent deadlock.
  + drop(guard);
  + // Note that `token()` only reloads if the cached token is expiring.
  + // A separate method to conditionally reload minimizes the need for an exclusive access.
  + bearer_header(token_file.write().await.token())
  }
  #[cfg(feature = "oauth")]
  @@ -279,7 +284,7 @@ impl TryFrom<&AuthInfo> for Auth {
  // Token file reference. Must be reloaded at least once a minute.
  if let Some(file) = &auth_info.token_file {
  return Ok(Self::RefreshableToken(RefreshableToken::File(Arc::new(
  - Mutex::new(TokenFile::new(file)?),
  + RwLock::new(TokenFile::new(file)?),
  ))));
  }
  