我在 actix-web 中有一个 Web 服务器,最近我构建了一个不同的 C++ 服务器。我决定实现gRPC作为两者之间的通信桥梁。但我不知道如何集成actix web + tonic(在http端点中调用gRPC调用)。我当前的解决方案是:
RPCRepository
保存所有rpc服务,并将其作为互斥体传递给app_data
(因为rpc函数由于某种未知原因是可变的)。
但这种方法似乎违反直觉,如果我同时有 1k 个连接,为什么他们必须等待互斥锁被解锁?
我想知道我的集成是否不合适或者这就是 actix-web+tonic grpc 的限制。
// grpc.rs
pub struct RPCClientRepository {
pub health_client: HealthCheckPingClient<Channel>,
pub suggest_client: SuggesterClient<Channel>,
}
... rest ...
// main.rs
let grpc_ctx = Data::new(Mutex::new(grpc_repo));
println!("[INFO] HTTP Server running at port {}", PORT);
HttpServer::new(move || {
App::new()
.app_data(ctx.clone())
.app_data(grpc_ctx.clone())
.service(activities)
})
.bind("0.0.0.0:".to_owned() + PORT)?
.run()
.await
// activities.rs
#[get("/activities")]
pub async fn activities(
req: HttpRequest,
ctx: Data<Driver>,
rpc_repo: Data<Mutex<RPCClientRepository>>,
) -> impl Responder {
let mut unlock = rpc_repo
.lock()
.unwrap();
let suggestion = unlock
.suggest_client
.suggest_friends(tonic::Request::new(SuggestRequest {
skip: 0,
user_id: "".to_string(),
}))
.await;
... rest ...
经过一番挖掘,收集了更多信息(希望是真的,如果我错了,请纠正我),我想我已经找到了答案。
我被告知 tonic 提供了一个非常有效的克隆,所以这就是方法,而不是等待 1 个互斥体。
// main.rs
let grpc_ctx = Data::new(Mutex::new(grpc_repo));
println!("[INFO] HTTP Server running at port {}", PORT);
HttpServer::new(move || {
App::new()
.app_data(ctx.clone())
.app_data(grpc_ctx.clone())
.service(activities)
})
.bind("0.0.0.0:".to_owned() + PORT)?
.run()
.await
// activities.rs
#[get("/activities")]
pub async fn activities(
req: HttpRequest,
ctx: Data<Driver>,
rpc_repo: Data<Mutex<RPCClientRepository>>,
) -> impl Responder {
let mut cl = rpc_repo.suggest_client.clone();
let res = cl.suggest_friends(tonic::Request::new(SuggestRequest {
skip: 0,
user_id: "id_123",
}))
.await;
let data = match res {
Ok(response) => response,
Err(e) => {
println!("[E] error at gRPC Activities: {}", e);
return HttpResponse::BadGateway().finish();
}
};
println!("c++ classifier returned: {} results",data.into_inner().count);
... rest ...