servers/grpc/
region_server.rs1use std::sync::Arc;
16
17use api::v1::region::region_server::Region as RegionServer;
18use api::v1::region::{RegionRequest, RegionResponse, region_request};
19use async_trait::async_trait;
20use common_error::ext::ErrorExt;
21use common_runtime::Runtime;
22use common_runtime::runtime::RuntimeTrait;
23use common_telemetry::tracing::info_span;
24use common_telemetry::tracing_context::{FutureExt, TracingContext};
25use common_telemetry::{debug, error, warn};
26use snafu::{OptionExt, ResultExt};
27use tonic::{Request, Response, Status};
28
29use crate::error::{InvalidQuerySnafu, JoinTaskSnafu, Result};
30use crate::grpc::{TonicResult, cancellation};
31
32#[async_trait]
33pub trait RegionServerHandler: Send + Sync {
34 async fn handle(&self, request: region_request::Body) -> Result<RegionResponse>;
35
36 async fn handle_region_request(&self, request: RegionRequest) -> Result<RegionResponse> {
37 let body = request.body.context(InvalidQuerySnafu {
38 reason: "Expecting non-empty region request body.",
39 })?;
40 self.handle(body).await
41 }
42}
43
44pub type RegionServerHandlerRef = Arc<dyn RegionServerHandler>;
45
46#[derive(Clone)]
47pub struct RegionServerRequestHandler {
48 handler: Arc<dyn RegionServerHandler>,
49 runtime: Runtime,
50}
51
52impl RegionServerRequestHandler {
53 pub fn new(handler: Arc<dyn RegionServerHandler>, runtime: Runtime) -> Self {
54 Self { handler, runtime }
55 }
56
57 async fn handle(&self, request: RegionRequest) -> Result<RegionResponse> {
58 let tracing_context = TracingContext::from_w3c(
59 &request
60 .header
61 .as_ref()
62 .context(InvalidQuerySnafu {
63 reason: "Expecting non-empty region request header.",
64 })?
65 .tracing_context,
66 );
67 let handler = self.handler.clone();
68
69 let handle = self.runtime.spawn(async move {
77 handler
78 .handle_region_request(request)
79 .trace(tracing_context.attach(info_span!("RegionServerRequestHandler::handle")))
80 .await
81 .map_err(|e| {
82 if e.status_code().should_log_error() {
83 error!(e; "Failed to handle request");
84 } else {
85 debug!("Failed to handle request, err: {}", e);
87 }
88 e
89 })
90 });
91
92 handle.await.context(JoinTaskSnafu)?
93 }
94}
95
96#[async_trait]
97impl RegionServer for RegionServerRequestHandler {
98 async fn handle(
99 &self,
100 request: Request<RegionRequest>,
101 ) -> TonicResult<Response<RegionResponse>> {
102 let remote_addr = request.remote_addr();
103 let self_cloned = self.clone();
104 let request_future = async move {
105 let request = request.into_inner();
106 let response = self_cloned.handle(request).await?;
107
108 Ok(Response::new(response))
109 };
110
111 let cancellation_future = async move {
112 warn!("Region request from {:?} cancelled by client", remote_addr);
113 Err(Status::cancelled("Region request cancelled by client"))
116 };
117 cancellation::with_cancellation_handler(request_future, cancellation_future).await
118 }
119}