tangled
alpha
login
or
join now
ptr.pet
/
hydrant
26
fork
atom
at protocol indexer with flexible filtering, xrpc queries, and a cursor-backed event stream, built on fjall
at-protocol
atproto
indexer
rust
fjall
26
fork
atom
overview
issues
6
pulls
pipelines
[ingest] refactor worker errors to IngestError
ptr.pet
3 weeks ago
8c239314
28795a0c
verified
This commit was signed with the committer's
known signature
.
ptr.pet
SSH Key Fingerprint:
SHA256:Abmvag+juovVufZTxyWY8KcVgrznxvBjQpJesv071Aw=
+34
-55
1 changed file
expand all
collapse all
unified
split
src
ingest
worker.rs
+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
22
+
use thiserror::Error;
22
23
use tokio::sync::mpsc;
23
24
use tracing::{debug, error, info, trace, warn};
24
25
25
25
-
#[derive(Debug)]
26
26
-
struct KeyFetchError(miette::Report);
26
26
+
#[derive(Debug, Diagnostic, Error)]
27
27
+
enum IngestError {
28
28
+
#[error("{0}")]
29
29
+
Generic(miette::Report),
27
30
28
28
-
impl std::fmt::Display for KeyFetchError {
29
29
-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30
30
-
write!(f, "{}", self.0)
31
31
-
}
32
32
-
}
31
31
+
#[error("key fetch failed: {0}")]
32
32
+
KeyFetch(smol_str::SmolStr),
33
33
+
34
34
+
#[error(transparent)]
35
35
+
#[diagnostic(transparent)]
36
36
+
Commit(#[from] CommitError),
33
37
34
34
-
impl std::error::Error for KeyFetchError {
35
35
-
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
36
36
-
self.0.source()
37
37
-
}
38
38
+
#[error(transparent)]
39
39
+
#[diagnostic(transparent)]
40
40
+
NoSigningKey(#[from] NoSigningKeyError),
38
41
}
39
42
40
40
-
impl Diagnostic for KeyFetchError {
41
41
-
fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
42
42
-
self.0.code()
43
43
-
}
44
44
-
45
45
-
fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
46
46
-
self.0.help()
47
47
-
}
48
48
-
49
49
-
fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
50
50
-
self.0.labels()
51
51
-
}
52
52
-
53
53
-
fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
54
54
-
self.0.diagnostic_source()
55
55
-
}
56
56
-
57
57
-
fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
58
58
-
self.0.related()
59
59
-
}
60
60
-
61
61
-
fn source_code(&self) -> Option<&dyn miette::SourceCode> {
62
62
-
self.0.source_code()
63
63
-
}
64
64
-
65
65
-
fn severity(&self) -> Option<miette::Severity> {
66
66
-
self.0.severity()
67
67
-
}
68
68
-
69
69
-
fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
70
70
-
self.0.url()
43
43
+
impl From<miette::Report> for IngestError {
44
44
+
fn from(report: miette::Report) -> Self {
45
45
+
IngestError::Generic(report)
71
46
}
72
47
}
73
48
···
280
255
}
281
256
Ok(RepoProcessResult::Syncing(None)) => {}
282
257
Err(e) => {
258
258
+
if let IngestError::Generic(e) = &e {
259
259
+
db::check_poisoned_report(e);
260
260
+
}
283
261
error!("error processing message for {did}: {e}");
284
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
325
-
fn check_if_retriable_failure(e: &miette::Report) -> bool {
326
326
-
e.downcast_ref::<KeyFetchError>().is_none()
327
327
-
&& e.downcast_ref::<CommitError>().is_none()
328
328
-
&& e.downcast_ref::<NoSigningKeyError>().is_none()
302
302
+
fn check_if_retriable_failure(e: &IngestError) -> bool {
303
303
+
!matches!(
304
304
+
e,
305
305
+
IngestError::KeyFetch(_) | IngestError::Commit(_) | IngestError::NoSigningKey(_)
306
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
335
-
) -> Result<RepoProcessResult<'s, 'c>> {
313
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
489
-
) -> Result<RepoProcessResult<'ns, 'c>> {
467
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
564
-
) -> Result<RepoProcessResult<'s, 'c>> {
542
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
643
-
) -> Result<RepoProcessResult<'s, 'static>> {
621
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
678
-
fn fetch_key(ctx: &WorkerContext, did: &Did) -> Result<Option<PublicKey<'static>>> {
656
656
+
fn fetch_key(
657
657
+
ctx: &WorkerContext,
658
658
+
did: &Did,
659
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
683
-
.map_err(|e| {
684
684
-
KeyFetchError(miette::miette!("failed to get pubkey for {did}: {e}"))
685
685
-
})?;
664
664
+
.map_err(|e| IngestError::KeyFetch(e.to_smolstr()))?;
686
665
Ok(Some(key))
687
666
} else {
688
667
Ok(None)