at protocol indexer with flexible filtering, xrpc queries, and a cursor-backed event stream, built on fjall
at-protocol atproto indexer rust fjall

[ingest] refactor worker errors to IngestError

ptr.pet 8c239314 28795a0c

verified
+34 -55
+34 -55
src/ingest/worker.rs
··· 19 19 use std::collections::{HashMap, HashSet, hash_map::DefaultHasher}; 20 20 use std::hash::{Hash, Hasher}; 21 21 use std::sync::Arc; 22 + use thiserror::Error; 22 23 use tokio::sync::mpsc; 23 24 use tracing::{debug, error, info, trace, warn}; 24 25 25 - #[derive(Debug)] 26 - struct KeyFetchError(miette::Report); 26 + #[derive(Debug, Diagnostic, Error)] 27 + enum IngestError { 28 + #[error("{0}")] 29 + Generic(miette::Report), 27 30 28 - impl std::fmt::Display for KeyFetchError { 29 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 30 - write!(f, "{}", self.0) 31 - } 32 - } 31 + #[error("key fetch failed: {0}")] 32 + KeyFetch(smol_str::SmolStr), 33 + 34 + #[error(transparent)] 35 + #[diagnostic(transparent)] 36 + Commit(#[from] CommitError), 33 37 34 - impl std::error::Error for KeyFetchError { 35 - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 36 - self.0.source() 37 - } 38 + #[error(transparent)] 39 + #[diagnostic(transparent)] 40 + NoSigningKey(#[from] NoSigningKeyError), 38 41 } 39 42 40 - impl Diagnostic for KeyFetchError { 41 - fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { 42 - self.0.code() 43 - } 44 - 45 - fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { 46 - self.0.help() 47 - } 48 - 49 - fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> { 50 - self.0.labels() 51 - } 52 - 53 - fn diagnostic_source(&self) -> Option<&dyn Diagnostic> { 54 - self.0.diagnostic_source() 55 - } 56 - 57 - fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> { 58 - self.0.related() 59 - } 60 - 61 - fn source_code(&self) -> Option<&dyn miette::SourceCode> { 62 - self.0.source_code() 63 - } 64 - 65 - fn severity(&self) -> Option<miette::Severity> { 66 - self.0.severity() 67 - } 68 - 69 - fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> { 70 - self.0.url() 43 + impl From<miette::Report> for IngestError { 44 + fn from(report: miette::Report) -> Self { 45 + IngestError::Generic(report) 71 46 } 72 47 } 73 48 ··· 280 255 } 281 256 Ok(RepoProcessResult::Syncing(None)) => {} 282 257 Err(e) => { 258 + if let IngestError::Generic(e) = &e { 259 + db::check_poisoned_report(e); 260 + } 283 261 error!("error processing message for {did}: {e}"); 284 - db::check_poisoned_report(&e); 285 262 if Self::check_if_retriable_failure(&e) { 286 263 if let SubscribeReposMessage::Commit(commit) = &msg { 287 264 if let Err(e) = ··· 322 299 323 300 // dont retry commit or sync on key fetch errors 324 301 // since we'll just try again later if we get commit or sync again 325 - fn check_if_retriable_failure(e: &miette::Report) -> bool { 326 - e.downcast_ref::<KeyFetchError>().is_none() 327 - && e.downcast_ref::<CommitError>().is_none() 328 - && e.downcast_ref::<NoSigningKeyError>().is_none() 302 + fn check_if_retriable_failure(e: &IngestError) -> bool { 303 + !matches!( 304 + e, 305 + IngestError::KeyFetch(_) | IngestError::Commit(_) | IngestError::NoSigningKey(_) 306 + ) 329 307 } 330 308 331 309 fn process_message<'s, 'c>( 332 310 ctx: &mut WorkerContext, 333 311 msg: &'c SubscribeReposMessage<'static>, 334 312 did: &Did, 335 - ) -> Result<RepoProcessResult<'s, 'c>> { 313 + ) -> Result<RepoProcessResult<'s, 'c>, IngestError> { 336 314 let check_repo_res = Self::check_repo_state(ctx, did, msg)?; 337 315 let mut repo_state = match check_repo_res { 338 316 RepoProcessResult::Syncing(_) | RepoProcessResult::Deleted => { ··· 486 464 did: &Did, 487 465 repo_state: RepoState<'s>, 488 466 commit: &'c Commit<'c>, 489 - ) -> Result<RepoProcessResult<'ns, 'c>> { 467 + ) -> Result<RepoProcessResult<'ns, 'c>, IngestError> { 490 468 // check for replayed events (already seen revision) 491 469 if matches!(repo_state.rev, Some(ref rev) if commit.rev.as_str() <= rev.to_tid().as_str()) { 492 470 debug!( ··· 561 539 ctx: &mut WorkerContext, 562 540 did: &Did<'_>, 563 541 msg: &'c SubscribeReposMessage<'static>, 564 - ) -> Result<RepoProcessResult<'s, 'c>> { 542 + ) -> Result<RepoProcessResult<'s, 'c>, IngestError> { 565 543 // check if we have this repo 566 544 if let Some(state) = ctx.repo_cache.get(did) { 567 545 return Ok(RepoProcessResult::Ok(state.clone())); ··· 640 618 ctx: &mut WorkerContext, 641 619 did: &Did, 642 620 mut repo_state: RepoState<'s>, 643 - ) -> Result<RepoProcessResult<'s, 'static>> { 621 + ) -> Result<RepoProcessResult<'s, 'static>, IngestError> { 644 622 let prefix = keys::resync_buffer_prefix(did); 645 623 646 624 for guard in ctx.state.db.resync_buffer.prefix(&prefix) { ··· 675 653 Ok(RepoProcessResult::Ok(repo_state)) 676 654 } 677 655 678 - fn fetch_key(ctx: &WorkerContext, did: &Did) -> Result<Option<PublicKey<'static>>> { 656 + fn fetch_key( 657 + ctx: &WorkerContext, 658 + did: &Did, 659 + ) -> Result<Option<PublicKey<'static>>, IngestError> { 679 660 if ctx.verify_signatures { 680 661 let key = ctx 681 662 .handle 682 663 .block_on(ctx.state.resolver.resolve_signing_key(did)) 683 - .map_err(|e| { 684 - KeyFetchError(miette::miette!("failed to get pubkey for {did}: {e}")) 685 - })?; 664 + .map_err(|e| IngestError::KeyFetch(e.to_smolstr()))?; 686 665 Ok(Some(key)) 687 666 } else { 688 667 Ok(None)