diff --git a/src/common/meta/src/instruction.rs b/src/common/meta/src/instruction.rs index 6ae074b0ac9..827f06e944d 100644 --- a/src/common/meta/src/instruction.rs +++ b/src/common/meta/src/instruction.rs @@ -49,7 +49,7 @@ pub struct InstructionError { pub message: String, /// Retry hint serialized as a string. #[serde( - serialize_with = "RetryHint::serialize_as_str", + serialize_with = "InstructionError::serialize_retry_hint", deserialize_with = "RetryHint::deserialize_from_str" )] pub retry_hint: RetryHint, @@ -108,6 +108,18 @@ impl InstructionError { retry_hint: error.retry_hint(), } } + + /// Keeps instruction replies readable by peers that only know the legacy hints. + fn serialize_retry_hint(hint: &RetryHint, serializer: S) -> Result + where + S: Serializer, + { + let hint = match hint { + RetryHint::RetryAfterRouteRefresh => RetryHint::Retryable, + hint => *hint, + }; + RetryHint::serialize_as_str(&hint, serializer) + } } impl Display for InstructionError { @@ -1450,6 +1462,26 @@ mod tests { ); } + #[test] + fn test_instruction_error_route_refresh_compatibility() { + let error = InstructionError::new( + StatusCode::RegionNotFound, + "region not found", + RetryHint::RetryAfterRouteRefresh, + ); + let serialized = serde_json::to_string(&error).unwrap(); + assert_eq!( + r#"{"code":4005,"message":"region not found","retry_hint":"retryable"}"#, + serialized + ); + let decoded: InstructionError = serde_json::from_str(&serialized).unwrap(); + assert_eq!(decoded.code, error.code); + assert_eq!(decoded.message, error.message); + assert_eq!(decoded.retry_hint, RetryHint::Retryable); + assert_eq!(error.retry_hint, RetryHint::RetryAfterRouteRefresh); + assert_eq!(error.retry_hint.as_str(), "retry_after_route_refresh"); + } + #[test] fn test_instruction_error_from_error() { let error = MockError::new(StatusCode::RegionNotFound);