autopush_common/db/bigtable/bigtable_client/
error.rs1use std::fmt::{self, Display};
2
3use actix_web::http::StatusCode;
4use deadpool::managed::{PoolError, TimeoutType};
5use thiserror::Error;
6
7use crate::errors::ReportableError;
8
9#[derive(PartialEq, Eq, Debug)]
10pub enum MutateRowStatus {
11 OK,
12 Cancelled,
13 Unknown,
14 InvalidArgument,
15 DeadlineExceeded,
16 NotFound,
17 AlreadyExists,
18 PermissionDenied,
19 ResourceExhausted,
20 FailedPrecondition,
21 Aborted,
22 OutOfRange,
23 Unimplemented,
24 Internal,
25 Unavailable,
26 DataLoss,
27 Unauthenticated,
28}
29
30impl MutateRowStatus {
31 pub fn is_ok(&self) -> bool {
32 self == &Self::OK
33 }
34}
35
36impl From<i32> for MutateRowStatus {
37 fn from(v: i32) -> Self {
38 match v {
39 0 => Self::OK,
40 1 => Self::Cancelled,
41 2 => Self::Unknown,
42 3 => Self::InvalidArgument,
43 4 => Self::DeadlineExceeded,
44 5 => Self::NotFound,
45 6 => Self::AlreadyExists,
46 7 => Self::PermissionDenied,
47 8 => Self::ResourceExhausted,
48 9 => Self::FailedPrecondition,
49 10 => Self::Aborted,
50 11 => Self::OutOfRange,
51 12 => Self::Unimplemented,
52 13 => Self::Internal,
53 14 => Self::Unavailable,
54 15 => Self::DataLoss,
55 16 => Self::Unauthenticated,
56 _ => Self::Unknown,
57 }
58 }
59}
60
61impl Display for MutateRowStatus {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.write_str(match self {
64 MutateRowStatus::OK => "Ok",
65 MutateRowStatus::Cancelled => "Cancelled",
66 MutateRowStatus::Unknown => "Unknown",
67 MutateRowStatus::InvalidArgument => "Invalid Argument",
68 MutateRowStatus::DeadlineExceeded => "Deadline Exceeded",
69 MutateRowStatus::NotFound => "Not Found",
70 MutateRowStatus::AlreadyExists => "Already Exists",
71 MutateRowStatus::PermissionDenied => "Permission Denied",
72 MutateRowStatus::ResourceExhausted => "Resource Exhausted",
73 MutateRowStatus::FailedPrecondition => "Failed Precondition",
74 MutateRowStatus::Aborted => "Aborted",
75 MutateRowStatus::OutOfRange => "Out of Range",
76 MutateRowStatus::Unimplemented => "Unimplemented",
77 MutateRowStatus::Internal => "Internal",
78 MutateRowStatus::Unavailable => "Unavailable",
79 MutateRowStatus::DataLoss => "Data Loss",
80 MutateRowStatus::Unauthenticated => "Unauthenticated",
81 })
82 }
83}
84
85impl MutateRowStatus {
86 pub fn status(&self) -> StatusCode {
87 match self {
88 MutateRowStatus::OK => StatusCode::OK,
89 MutateRowStatus::Aborted
91 | MutateRowStatus::DeadlineExceeded
92 | MutateRowStatus::Internal
93 | MutateRowStatus::ResourceExhausted
94 | MutateRowStatus::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
95 _ => StatusCode::INTERNAL_SERVER_ERROR,
96 }
97 }
98}
99
100#[derive(Debug, Error)]
101pub enum BigTableError {
102 #[error("Invalid Row Response: {0}")]
103 InvalidRowResponse(#[source] grpcio::Error),
104
105 #[error("Invalid Chunk")]
106 InvalidChunk(String),
107
108 #[error("BigTable read error: {0}")]
109 Read(#[source] grpcio::Error),
110
111 #[error("BigTable write timestamp error: {0}")]
112 WriteTime(#[source] std::time::SystemTimeError),
113
114 #[error("Bigtable write error: {0}")]
115 Write(#[source] grpcio::Error),
116
117 #[error("GRPC Error: {0}")]
118 GRPC(#[source] grpcio::Error),
119
120 #[error("Bigtable status response: {0:?}")]
123 Status(MutateRowStatus, String),
124
125 #[error("BigTable Admin Error: {0}")]
126 Admin(String, Option<String>),
127
128 #[error("Pool Error: {0}")]
130 Pool(Box<PoolError<BigTableError>>),
131
132 #[error("Pool Timeout: {0:?}")]
134 PoolTimeout(TimeoutType),
135
136 #[error("BigTable config error: {0}")]
137 Config(String),
138}
139
140impl BigTableError {
141 pub fn status(&self) -> StatusCode {
142 match self {
143 BigTableError::PoolTimeout(_) => StatusCode::SERVICE_UNAVAILABLE,
144 BigTableError::Status(e, _) => e.status(),
145 _ => StatusCode::INTERNAL_SERVER_ERROR,
146 }
147 }
148}
149
150impl ReportableError for BigTableError {
151 fn is_sentry_event(&self) -> bool {
152 #[allow(clippy::match_like_matches_macro)]
153 match self {
154 BigTableError::PoolTimeout(_) => false,
155 _ => true,
156 }
157 }
158
159 fn metric_label(&self) -> Option<&'static str> {
160 let err = match self {
161 BigTableError::InvalidRowResponse(_) => "storage.bigtable.error.invalid_row_response",
162 BigTableError::InvalidChunk(_) => "storage.bigtable.error.invalid_chunk",
163 BigTableError::Read(_) => "storage.bigtable.error.read",
164 BigTableError::Write(_) => "storage.bigtable.error.write",
165 BigTableError::Status(_, _) => "storage.bigtable.error.status",
166 BigTableError::WriteTime(_) => "storage.bigtable.error.writetime",
167 BigTableError::Admin(_, _) => "storage.bigtable.error.admin",
168 BigTableError::Pool(_) => "storage.bigtable.error.pool",
169 BigTableError::PoolTimeout(_) => "storage.bigtable.error.pool_timeout",
170 BigTableError::GRPC(_) => "storage.bigtable.error.grpc",
171 BigTableError::Config(_) => "storage.bigtable.error.config",
172 };
173 Some(err)
174 }
175
176 fn tags(&self) -> Vec<(&str, String)> {
177 #[allow(clippy::match_like_matches_macro)]
178 match self {
179 BigTableError::PoolTimeout(tt) => vec![("type", format!("{tt:?}").to_lowercase())],
180 _ => vec![],
181 }
182 }
183
184 fn extras(&self) -> Vec<(&str, String)> {
185 match self {
186 BigTableError::InvalidRowResponse(s) => vec![("error", s.to_string())],
187 BigTableError::InvalidChunk(s) => vec![("error", s.to_string())],
188 BigTableError::GRPC(s) => vec![("error", s.to_string())],
189 BigTableError::Read(s) => vec![("error", s.to_string())],
190 BigTableError::Write(s) => vec![("error", s.to_string())],
191 BigTableError::Status(code, s) => {
192 vec![("code", code.to_string()), ("error", s.to_string())]
193 }
194 BigTableError::WriteTime(s) => vec![("error", s.to_string())],
195 BigTableError::Admin(s, raw) => {
196 let mut x = vec![("error", s.to_owned())];
197 if let Some(raw) = raw {
198 x.push(("raw", raw.to_string()));
199 };
200 x
201 }
202 BigTableError::Pool(e) => vec![("error", e.to_string())],
203 _ => vec![],
204 }
205 }
206}