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, 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    #[snafu(display("Failed to convert meta config"))]
121    ConvertMetaConfig {
122        #[snafu(implicit)]
123        location: Location,
124        #[snafu(source)]
125        error: serde_json::Error,
126    },
127}
128
129#[allow(dead_code)]
130pub type Result<T> = std::result::Result<T, Error>;
131
132impl ErrorExt for Error {
133    fn as_any(&self) -> &dyn std::any::Any {
134        self
135    }
136
137    fn status_code(&self) -> StatusCode {
138        match self {
139            Error::IllegalGrpcClientState { .. }
140            | Error::NoLeader { .. }
141            | Error::AskLeaderTimeout { .. }
142            | Error::NotStarted { .. }
143            | Error::SendHeartbeat { .. }
144            | Error::CreateHeartbeatStream { .. }
145            | Error::CreateChannel { .. }
146            | Error::RetryTimesExceeded { .. }
147            | Error::ReadOnlyKvBackend { .. }
148            | Error::ConvertMetaConfig { .. } => StatusCode::Internal,
149
150            Error::MetaServer { code, .. } => *code,
151
152            Error::InvalidResponseHeader { source, .. }
153            | Error::ConvertMetaRequest { source, .. }
154            | Error::ConvertMetaResponse { source, .. }
155            | Error::GetFlowStat { source, .. } => source.status_code(),
156        }
157    }
158}
159
160impl Error {
161    pub fn is_exceeded_size_limit(&self) -> bool {
162        matches!(
163            self,
164            Error::MetaServer {
165                tonic_code: tonic::Code::OutOfRange,
166                ..
167            }
168        )
169    }
170}
171
172define_from_tonic_status!(Error, MetaServer);