使用 tonic::Status 和 redis::RedisError 的 Redis 和 Tonic 异步应用程序的正确错误处理

Proper Error handling for a Redis and Tonic async application with tonic::Status and redis::RedisError

我正在制作一个使用 Redis 客户端的基于 Tonic 的 gRPC 微服务。我想不出在发生异步错误时将 RedisError 隐式转换为 tonic::Status 的示例。

async fn make_transaction(
        &self,
        request: Request<TransactionRequest>,
    ) -> Result<Response<TransactionResponse>, Status> {

    let mut con = self.client.get_async_connection().await?;
    con.set("my_key", 42).await?;

来自Redis 客户端的连接可能会像设置一样失败。我正在使用使用 Tokio 的异步接口。我宁愿不 map 错误,因为这似乎会破坏异步。

我在想我需要实现特征 From<Status>From<RedisError 但不确定如何去做。这是我的尝试,但它不起作用,因为 Tonic 想要一个 tonic::Status 结构而不是我制作的 ApiError 结构:


pub struct ApiError {
}

impl From<tonic::Status> for ApiError {
    fn from(err: Status) -> ApiError {
        ApiError {  }
    }
}

impl From<RedisError> for Status {
    fn from(err: redis::RedisError) -> ApiError {
        ApiError {  }
    }
}

我今天遇到了类似的问题。我设法通过使用自定义类型作为原始错误(在您的情况下是 RedisError)的过渡容器来解决它,因此类似以下的内容也可能对您有用:

pub struct ApiError {}

impl From<RedisError> for ApiError {
    fn from(err: redis::RedisError) -> Self {
        Self { }
    }
}

impl From<ApiError> for Status {
  fn from(err: ApiError) -> Self {
        Self::internal("Failed talking to Redis")
    }
}

async fn set_key(client: ..., key: &str, value: i64) -> Result<(), ApiError> {
  let mut con = client.get_async_connection().await?;
  con.set(key, value).await?
}

async fn make_transaction(
        &self,
        request: Request<TransactionRequest>,
    ) -> Result<Response<TransactionResponse>, Status> {

  set_key(self.client, "my_key".into(), 42).await?
}

但我是 Rust 菜鸟,所以我不确定这是否是最好的方法...