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 #[error("Circuit breaker open: BigTable temporarily unavailable")]
140 CircuitBreakerOpen,
141}
142
143impl BigTableError {
144 pub fn status(&self) -> StatusCode {
145 match self {
146 BigTableError::PoolTimeout(_) | BigTableError::CircuitBreakerOpen => {
147 StatusCode::SERVICE_UNAVAILABLE
148 }
149 BigTableError::Status(e, _) => e.status(),
150 _ => StatusCode::INTERNAL_SERVER_ERROR,
151 }
152 }
153}
154
155impl ReportableError for BigTableError {
156 fn is_sentry_event(&self) -> bool {
157 #[allow(clippy::match_like_matches_macro)]
158 match self {
159 BigTableError::PoolTimeout(_) | BigTableError::CircuitBreakerOpen => false,
160 _ => true,
161 }
162 }
163
164 fn metric_label(&self) -> Option<&'static str> {
165 let err = match self {
166 BigTableError::InvalidRowResponse(_) => "storage.bigtable.error.invalid_row_response",
167 BigTableError::InvalidChunk(_) => "storage.bigtable.error.invalid_chunk",
168 BigTableError::Read(_) => "storage.bigtable.error.read",
169 BigTableError::Write(_) => "storage.bigtable.error.write",
170 BigTableError::Status(_, _) => "storage.bigtable.error.status",
171 BigTableError::WriteTime(_) => "storage.bigtable.error.writetime",
172 BigTableError::Admin(_, _) => "storage.bigtable.error.admin",
173 BigTableError::Pool(_) => "storage.bigtable.error.pool",
174 BigTableError::PoolTimeout(_) => "storage.bigtable.error.pool_timeout",
175 BigTableError::GRPC(_) => "storage.bigtable.error.grpc",
176 BigTableError::Config(_) => "storage.bigtable.error.config",
177 BigTableError::CircuitBreakerOpen => "storage.bigtable.error.circuit_breaker",
178 };
179 Some(err)
180 }
181
182 fn tags(&self) -> Vec<(&str, String)> {
183 #[allow(clippy::match_like_matches_macro)]
184 match self {
185 BigTableError::PoolTimeout(tt) => vec![("type", format!("{tt:?}").to_lowercase())],
186 _ => vec![],
187 }
188 }
189
190 fn extras(&self) -> Vec<(&str, String)> {
191 match self {
192 BigTableError::InvalidRowResponse(s) => vec![("error", s.to_string())],
193 BigTableError::InvalidChunk(s) => vec![("error", s.to_string())],
194 BigTableError::GRPC(s) => vec![("error", s.to_string())],
195 BigTableError::Read(s) => vec![("error", s.to_string())],
196 BigTableError::Write(s) => vec![("error", s.to_string())],
197 BigTableError::Status(code, s) => {
198 vec![("code", code.to_string()), ("error", s.to_string())]
199 }
200 BigTableError::WriteTime(s) => vec![("error", s.to_string())],
201 BigTableError::Admin(s, raw) => {
202 let mut x = vec![("error", s.to_owned())];
203 if let Some(raw) = raw {
204 x.push(("raw", raw.to_string()));
205 };
206 x
207 }
208 BigTableError::Pool(e) => vec![("error", e.to_string())],
209 _ => vec![],
210 }
211 }
212}