Returns `true` if the error is transient and worth retrying. Walks the `miette::Report` error chain looking for a `tonic::Status`. If found, only the gRPC codes that represent transient failures are retryable. If no `tonic::Status` is present (e.g. a raw connection error), assume the failure is transient.
(err: &miette::Report)
| 1294 | /// If no `tonic::Status` is present (e.g. a raw connection error), assume the |
| 1295 | /// failure is transient. |
| 1296 | fn is_retryable_error(err: &miette::Report) -> bool { |
| 1297 | let mut source: Option<&dyn std::error::Error> = Some(err.as_ref()); |
| 1298 | while let Some(e) = source { |
| 1299 | if let Some(status) = e.downcast_ref::<tonic::Status>() { |
| 1300 | return matches!( |
| 1301 | status.code(), |
| 1302 | tonic::Code::Unavailable |
| 1303 | | tonic::Code::DeadlineExceeded |
| 1304 | | tonic::Code::ResourceExhausted |
| 1305 | | tonic::Code::Aborted |
| 1306 | | tonic::Code::Internal |
| 1307 | | tonic::Code::Unknown |
| 1308 | ); |
| 1309 | } |
| 1310 | source = e.source(); |
| 1311 | } |
| 1312 | true |
| 1313 | } |
| 1314 | |
| 1315 | /// Retry a gRPC operation with exponential backoff (capped at 4 s). |
| 1316 | /// |