使用 Tonic 时如何处理外部错误,而我必须使用 tonic::Status?

Rob*_*son 4 redis rust tonic

我正在制作一个使用 Redis 客户端的基于 Tonic 的 gRPC 微服务。我无法找出发生异步错误时将 a 隐式转换RedisError为 a的示例。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?;
    ...
}
Run Code Online (Sandbox Code Playgroud)

来自 Redis 客户端的连接可能会失败以及设置失败。我宁愿不使用,.map_err()因为这似乎会破坏异步。

我想我需要实现这个特性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 {  }
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 7

我设法通过使用自定义类型作为原始错误(在RedisError您的情况下)的过渡容器来解决此类问题,因此类似以下内容也可能适合您:

pub struct ApiError {}

impl From<RedisError> for ApiError {
    fn from(err: 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?
}
Run Code Online (Sandbox Code Playgroud)

我不确定这是否是最好的方法,但似乎可以完成这项工作。