Skip to content

Commit 0bcfb67

Browse files
special case ApplicationFailure during ActivityError construciton
1 parent db7c2f1 commit 0bcfb67

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

crates/sdk/src/activities.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,10 @@ where
270270
E: Into<anyhow::Error>,
271271
{
272272
fn from(source: E) -> Self {
273-
Self::Application(ApplicationFailure::new(source).into())
273+
match source.into().downcast::<ApplicationFailure>() {
274+
Ok(application_failure) => Self::Application(Box::new(application_failure)),
275+
Err(err) => Self::Application(ApplicationFailure::new(err).into()),
276+
}
274277
}
275278
}
276279

@@ -424,3 +427,52 @@ impl Debug for ActivityDefinitions {
424427
.finish()
425428
}
426429
}
430+
431+
#[cfg(test)]
432+
mod test {
433+
use super::*;
434+
use rstest::rstest;
435+
436+
#[rstest]
437+
#[case(true)]
438+
#[case(false)]
439+
fn activity_error_conversion_is_not_lossy(#[case] non_retryable: bool) {
440+
use temporalio_common::protos::temporal::api::enums::v1::ApplicationErrorCategory;
441+
442+
let original = ApplicationFailure::builder(anyhow::anyhow!("big boom"))
443+
.type_name("BigBoom".to_owned())
444+
.non_retryable(non_retryable)
445+
.next_retry_delay(StdDuration::from_secs(3))
446+
.category(ApplicationErrorCategory::Benign)
447+
.details("details")
448+
.build();
449+
let err = ActivityError::from(original);
450+
let ActivityError::Application(actual) = err else {
451+
panic!("application failure should become app failure")
452+
};
453+
assert_eq!(actual.type_name(), Some("BigBoom"));
454+
assert_eq!(actual.is_non_retryable(), non_retryable);
455+
assert_eq!(actual.next_retry_delay(), Some(StdDuration::from_secs(3)));
456+
assert_eq!(actual.category(), ApplicationErrorCategory::Benign);
457+
assert_eq!(actual.to_string(), "big boom");
458+
}
459+
460+
#[test]
461+
fn activity_error_from_special_err_becomes_application() {
462+
#[derive(Debug, PartialEq)]
463+
struct MyError;
464+
465+
impl std::error::Error for MyError {}
466+
impl std::fmt::Display for MyError {
467+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468+
f.write_str("MyError")
469+
}
470+
}
471+
472+
let err = ActivityError::from(MyError);
473+
let ActivityError::Application(actual) = err else {
474+
panic!("expected application failure, got {err:?}")
475+
};
476+
assert_eq!(actual.to_string(), "MyError");
477+
}
478+
}

0 commit comments

Comments
 (0)