meta_client/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use common_error::define_from_tonic_status;
16use common_error::ext::ErrorExt;
17use common_error::status_code::StatusCode;
18use common_macro::stack_trace_debug;
19use snafu::{location, Location, Snafu};
20
21#[derive(Snafu)]
22#[snafu(visibility(pub))]
23#[stack_trace_debug]
24pub enum Error {
25    #[snafu(display("Illegal GRPC client state: {}", err_msg))]
26    IllegalGrpcClientState {
27        err_msg: String,
28        #[snafu(implicit)]
29        location: Location,
30    },
31
32    #[snafu(display("{}", msg))]
33    MetaServer {
34        code: StatusCode,
35        msg: String,
36        tonic_code: tonic::Code,
37        #[snafu(implicit)]
38        location: Location,
39    },
40
41    #[snafu(display("No leader, should ask leader first"))]
42    NoLeader {
43        #[snafu(implicit)]
44        location: Location,
45    },
46
47    #[snafu(display("Ask leader timeout"))]
48    AskLeaderTimeout {
49        #[snafu(implicit)]
50        location: Location,
51        #[snafu(source)]
52        error: tokio::time::error::Elapsed,
53    },
54
55    #[snafu(display("Failed to create gRPC channel"))]
56    CreateChannel {
57        #[snafu(implicit)]
58        location: Location,
59        source: common_grpc::error::Error,
60    },
61
62    #[snafu(display("{} not started", name))]
63    NotStarted {
64        name: String,
65        #[snafu(implicit)]
66        location: Location,
67    },
68
69    #[snafu(display("Failed to send heartbeat: {}", err_msg))]
70    SendHeartbeat {
71        err_msg: String,
72        #[snafu(implicit)]
73        location: Location,
74    },
75
76    #[snafu(display("Failed create heartbeat stream to server"))]
77    CreateHeartbeatStream {
78        #[snafu(implicit)]
79        location: Location,
80    },
81
82    #[snafu(display("Invalid response header"))]
83    InvalidResponseHeader {
84        #[snafu(implicit)]
85        location: Location,
86        source: common_meta::error::Error,
87    },
88
89    #[snafu(display("Failed to convert Metasrv request"))]
90    ConvertMetaRequest {
91        #[snafu(implicit)]
92        location: Location,
93        source: common_meta::error::Error,
94    },
95
96    #[snafu(display("Failed to convert Metasrv response"))]
97    ConvertMetaResponse {
98        #[snafu(implicit)]
99        location: Location,
100        source: common_meta::error::Error,
101    },
102
103    #[snafu(display("Failed to get flow stat"))]
104    GetFlowStat {
105        #[snafu(implicit)]
106        location: Location,
107        source: common_meta::error::Error,
108    },
109
110    #[snafu(display("Retry exceeded max times({}), message: {}", times, msg))]
111    RetryTimesExceeded { times: usize, msg: String },
112
113    #[snafu(display("Trying to write to a read-only kv backend: {}", name))]
114    ReadOnlyKvBackend {
115        name: String,
116        #[snafu(implicit)]
117        location: Location,
118    },
119}
120
121#[allow(dead_code)]
122pub type Result<T> = std::result::Result<T, Error>;
123
124impl ErrorExt for Error {
125    fn as_any(&self) -> &dyn std::any::Any {
126        self
127    }
128
129    fn status_code(&self) -> StatusCode {
130        match self {
131            Error::IllegalGrpcClientState { .. }
132            | Error::NoLeader { .. }
133            | Error::AskLeaderTimeout { .. }
134            | Error::NotStarted { .. }
135            | Error::SendHeartbeat { .. }
136            | Error::CreateHeartbeatStream { .. }
137            | Error::CreateChannel { .. }
138            | Error::RetryTimesExceeded { .. }
139            | Error::ReadOnlyKvBackend { .. } => StatusCode::Internal,
140
141            Error::MetaServer { code, .. } => *code,
142
143            Error::InvalidResponseHeader { source, .. }
144            | Error::ConvertMetaRequest { source, .. }
145            | Error::ConvertMetaResponse { source, .. }
146            | Error::GetFlowStat { source, .. } => source.status_code(),
147        }
148    }
149}
150
151impl Error {
152    pub fn is_exceeded_size_limit(&self) -> bool {
153        matches!(
154            self,
155            Error::MetaServer {
156                tonic_code: tonic::Code::OutOfRange,
157                ..
158            }
159        )
160    }
161}
162
163define_from_tonic_status!(Error, MetaServer);