Проблема с прицелом Arc и RwLock в ржавчине

столкнулся с проблемой, как показано ниже, нужно ли мне использовать &'static self или self вместо &self? Есть ли другое решение? Благодарен за любую помощь

struct AuthToken {
    token: String,
    expires_at: i64,
}



pub(crate) struct Notifier {
    credential: Credential,
    auth_token: Arc<RwLock<AuthToken>>,
    http_client: reqwest::Client,
}

pub(crate) async fn push_notification<D>(&self, notification: PushNotificationBody<D>) -> Result<(), Error>
    where
        D: Serialize,
    {
        {
            // error occurs here 
            let mut auth_token = self
                .auth_token
                .write()
                .map_err(|e| Error::wrap(e, "获取读写锁失败(fcm notifier)", 500u16))?;
            let timestamp = chrono::Utc::now().timestamp();
            if auth_token.expires_at <= timestamp - 300 {
                let token = Self::generate_jwt_token(&self.credential, timestamp)?;
                auth_token.token = token;
                auth_token.expires_at = timestamp + 3600;
            }
        }
...
}

@kmdreko ок, я отредактировал

wangjun 10.08.2024 05:49

И ошибку, пожалуйста. И можете ли вы уточнить, какой тип Error вы возвращаете?

kmdreko 10.08.2024 06:01
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
3
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хотя об этом сложно судить на основании предоставленной информации (определение Error было бы полезно, в частности Error::wrap()), проблема, скорее всего, будет заключаться в обработке ошибок в случае, если RwLock не удается заблокировать:

Помните, что RwLock::write() возвращает LockResult<RwLockWriteGuard<'_, T>>. В случае сбоя блокировки LockResult сопровождается PoisonError<RwLockWriteGuard<'_, T>>. У этого PoisonError есть into_inner()-метод, который позволяет получить доступ к базовым данным независимо от того, что блокировка считается отравленной (если это необходимо). Это также требует, чтобы PoisonError имел тот же срок жизни, что и RwLockWriteGuard, поскольку нам нужно иметь возможность разблокировать замок, пока внутренний RwLockWriteGuard отбрасывается. Другими словами, значение блокировки Mutex или RwLock, указывающее на ошибку, заблокировало базовый объект и содержит ссылку на эту блокировку, чтобы разблокировать ее. Это распространенный источник путаницы в Rust.

В вашей конкретной ситуации кажется, что ваш Error-тип может содержать значение ошибки e. Для этого потребуется, чтобы ссылка на lock имела всю жизнь 'static, чтобы вернуть эту ошибку из метода. Но RwLockWriteGuard, содержащийся в PoisonError, заимствован из self.auth_token, поэтому он существует ровно столько, сколько self. Это ошибка, которую вы получаете.

Решение состоит в том, чтобы удалить PoisonError (следовательно, разблокировать блокировку и удалить заимствование на &self) в map_err()-вызове.

Я провел рефакторинг своего кода и поднял Arc и Mutex до их родительской структуры, похоже, это помогло обойти проблему. Но я согласен с вами, причиной может быть LockResult. Позже я попробую ваше решение, чтобы убедиться, что вызвало проблему, и большое спасибо за ваш ответ.

wangjun 10.08.2024 16:01

Другие вопросы по теме