mirror of
https://github.com/lahfir/agent-desktop.git
synced 2026-07-27 01:22:16 +00:00
refactor: share transient resolution classification
This commit is contained in:
parent
c137343e23
commit
ff278ada56
3 changed files with 53 additions and 24 deletions
|
|
@ -56,6 +56,16 @@ impl AdapterError {
|
|||
self.retryability == crate::retryability::Retryability::Retryable
|
||||
}
|
||||
|
||||
pub(crate) fn is_retryable_resolution_failure(&self) -> bool {
|
||||
matches!(
|
||||
self.code,
|
||||
ErrorCode::StaleRef
|
||||
| ErrorCode::AmbiguousTarget
|
||||
| ErrorCode::Timeout
|
||||
| ErrorCode::AppUnresponsive
|
||||
) && self.is_explicitly_retryable()
|
||||
}
|
||||
|
||||
pub fn permits_retry_by_default(&self) -> bool {
|
||||
self.retryability != crate::retryability::Retryability::NonRetryable
|
||||
}
|
||||
|
|
@ -221,4 +231,40 @@ mod tests {
|
|||
assert!(!error.is_explicitly_retryable());
|
||||
assert!(!error.permits_retry_by_default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retryable_resolution_failure_characterizes_every_error_code() {
|
||||
let all = [
|
||||
ErrorCode::PermDenied,
|
||||
ErrorCode::ElementNotFound,
|
||||
ErrorCode::AppNotFound,
|
||||
ErrorCode::ActionFailed,
|
||||
ErrorCode::ActionNotSupported,
|
||||
ErrorCode::StaleRef,
|
||||
ErrorCode::AmbiguousTarget,
|
||||
ErrorCode::WindowNotFound,
|
||||
ErrorCode::PlatformNotSupported,
|
||||
ErrorCode::Timeout,
|
||||
ErrorCode::InvalidArgs,
|
||||
ErrorCode::NotificationNotFound,
|
||||
ErrorCode::SnapshotNotFound,
|
||||
ErrorCode::PolicyDenied,
|
||||
ErrorCode::AppUnresponsive,
|
||||
ErrorCode::Internal,
|
||||
];
|
||||
let retryable = [
|
||||
ErrorCode::StaleRef,
|
||||
ErrorCode::AmbiguousTarget,
|
||||
ErrorCode::Timeout,
|
||||
ErrorCode::AppUnresponsive,
|
||||
];
|
||||
|
||||
for code in all {
|
||||
let expected = retryable.contains(&code);
|
||||
let error = AdapterError::new(code.clone(), "failure")
|
||||
.with_details(serde_json::json!({ "retryable": true }));
|
||||
assert_eq!(error.is_retryable_resolution_failure(), expected);
|
||||
assert!(!AdapterError::new(code, "failure").is_retryable_resolution_failure());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,24 +223,17 @@ fn point_observed_bounds_hash(err: &AppError) -> Option<u64> {
|
|||
}
|
||||
|
||||
fn is_retryable_point_error(err: &AppError) -> bool {
|
||||
match err.code() {
|
||||
"STALE_REF" | "AMBIGUOUS_TARGET" | "TIMEOUT" | "APP_UNRESPONSIVE" => {
|
||||
error_is_explicitly_retryable(err)
|
||||
match err {
|
||||
AppError::Adapter(error) if error.is_retryable_resolution_failure() => true,
|
||||
AppError::Adapter(error) if error.code == crate::ErrorCode::ActionFailed => {
|
||||
["visible", "stable", "receives_events"]
|
||||
.into_iter()
|
||||
.any(|check| point_failed_check(err, check))
|
||||
}
|
||||
"ACTION_FAILED" => ["visible", "stable", "receives_events"]
|
||||
.into_iter()
|
||||
.any(|check| point_failed_check(err, check)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_is_explicitly_retryable(err: &AppError) -> bool {
|
||||
let AppError::Adapter(error) = err else {
|
||||
return false;
|
||||
};
|
||||
error.is_explicitly_retryable()
|
||||
}
|
||||
|
||||
fn point_failed_check(err: &AppError, expected: &str) -> bool {
|
||||
let AppError::Adapter(error) = err else {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ fn handle_resolve_failure(
|
|||
error: AdapterError,
|
||||
deadline: Deadline,
|
||||
) -> Result<(), AdapterError> {
|
||||
if is_permanent_error(&error.code) || !is_retryable_resolve_error(&error) {
|
||||
if !error.is_retryable_resolution_failure() {
|
||||
trace_resolve_error(context.context, context.ref_id, &error);
|
||||
return Err(error);
|
||||
}
|
||||
|
|
@ -125,16 +125,6 @@ fn is_permanent_actionability_error(code: &ErrorCode) -> bool {
|
|||
is_permanent_error(code) || matches!(code, ErrorCode::StaleRef | ErrorCode::AmbiguousTarget)
|
||||
}
|
||||
|
||||
fn is_retryable_resolve_error(error: &AdapterError) -> bool {
|
||||
matches!(
|
||||
error.code,
|
||||
ErrorCode::StaleRef
|
||||
| ErrorCode::AmbiguousTarget
|
||||
| ErrorCode::Timeout
|
||||
| ErrorCode::AppUnresponsive
|
||||
) && error.is_explicitly_retryable()
|
||||
}
|
||||
|
||||
fn timeout(state: &RefActionPollState, deadline: Deadline) -> AdapterError {
|
||||
let mut details = json!({
|
||||
"kind": "actionability_timeout",
|
||||
|
|
|
|||
Loading…
Reference in a new issue