From 06118a8fa60439f7400b3e6dea88e4cc198ca6d3 Mon Sep 17 00:00:00 2001 From: Charles Lowell <10964656+chlowell@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:14:29 +0000 Subject: [PATCH 1/5] Add retryable status codes to PipelineOptions --- sdk/core/azure_core/src/http/pipeline.rs | 1 + sdk/core/typespec_client_core/CHANGELOG.md | 1 + .../src/http/options/mod.rs | 11 +- .../src/http/options/retry.rs | 16 +- .../typespec_client_core/src/http/pipeline.rs | 18 +-- .../src/http/policies/retry/exponential.rs | 13 +- .../src/http/policies/retry/fixed.rs | 12 +- .../src/http/policies/retry/mod.rs | 138 +++++++++++++++++- 8 files changed, 187 insertions(+), 23 deletions(-) diff --git a/sdk/core/azure_core/src/http/pipeline.rs b/sdk/core/azure_core/src/http/pipeline.rs index 19b8ef3ce0..a42bc96f34 100644 --- a/sdk/core/azure_core/src/http/pipeline.rs +++ b/sdk/core/azure_core/src/http/pipeline.rs @@ -174,6 +174,7 @@ impl Pipeline { retry_headers: RetryHeaders { retry_headers: vec![X_MS_RETRY_AFTER_MS, RETRY_AFTER_MS, RETRY_AFTER], }, + ..PipelineOptions::default() }); Self(http::Pipeline::new( diff --git a/sdk/core/typespec_client_core/CHANGELOG.md b/sdk/core/typespec_client_core/CHANGELOG.md index a5b3ef6fa4..383d35dc8e 100644 --- a/sdk/core/typespec_client_core/CHANGELOG.md +++ b/sdk/core/typespec_client_core/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features Added +- Added `PipelineOptions::retry_status_codes` for configuring which status codes should trigger a retry. - Added `UrlExt::append_path()`. ### Breaking Changes diff --git a/sdk/core/typespec_client_core/src/http/options/mod.rs b/sdk/core/typespec_client_core/src/http/options/mod.rs index 2f680d26bb..2ec0183819 100644 --- a/sdk/core/typespec_client_core/src/http/options/mod.rs +++ b/sdk/core/typespec_client_core/src/http/options/mod.rs @@ -12,7 +12,7 @@ pub use transport::*; use crate::http::{ headers::RETRY_AFTER, policies::{Policy, RetryHeaders}, - Context, + Context, StatusCode, }; use std::borrow::Cow; use std::fmt::Debug; @@ -64,7 +64,15 @@ pub struct ClientMethodOptions<'a> { pub struct PipelineOptions { /// The set of headers which should be considered when /// determining the interval to wait for retry attempts. + /// This field doesn't apply to custom retry policies. pub retry_headers: RetryHeaders, + + /// The status codes that should trigger retries. This + /// field doesn't apply to custom retry policies. + /// + /// When empty, the default retry status codes are used as + /// described by [`crate::http::policies::RetryPolicy::get_retry_status_codes`]. + pub retry_status_codes: Vec, } impl Default for PipelineOptions { @@ -73,6 +81,7 @@ impl Default for PipelineOptions { retry_headers: RetryHeaders { retry_headers: vec![RETRY_AFTER], }, + retry_status_codes: Vec::new(), } } } diff --git a/sdk/core/typespec_client_core/src/http/options/retry.rs b/sdk/core/typespec_client_core/src/http/options/retry.rs index c002bdc7a1..19edaebb07 100644 --- a/sdk/core/typespec_client_core/src/http/options/retry.rs +++ b/sdk/core/typespec_client_core/src/http/options/retry.rs @@ -2,8 +2,12 @@ // Licensed under the MIT License. use crate::{ - http::policies::{ - ExponentialRetryPolicy, FixedRetryPolicy, NoRetryPolicy, Policy, RetryHeaders, RetryPolicy, + http::{ + policies::{ + ExponentialRetryPolicy, FixedRetryPolicy, NoRetryPolicy, Policy, RetryHeaders, + RetryPolicy, + }, + StatusCode, }, time::Duration, }; @@ -87,7 +91,11 @@ impl RetryOptions { } } - pub(crate) fn to_policy(&self, retry_headers: RetryHeaders) -> Arc { + pub(crate) fn to_policy( + &self, + retry_headers: RetryHeaders, + status_codes: &[StatusCode], + ) -> Arc { match &self.mode { RetryMode::Exponential(options) => Arc::new(ExponentialRetryPolicy::new( options.initial_delay, @@ -95,12 +103,14 @@ impl RetryOptions { options.max_total_elapsed, options.max_delay, retry_headers, + status_codes.to_vec(), )), RetryMode::Fixed(options) => Arc::new(FixedRetryPolicy::new( options.delay, options.max_retries, options.max_total_elapsed, retry_headers, + status_codes.to_vec(), )), RetryMode::Custom(c) => c.clone(), RetryMode::None => Arc::new(NoRetryPolicy::new(retry_headers)), diff --git a/sdk/core/typespec_client_core/src/http/pipeline.rs b/sdk/core/typespec_client_core/src/http/pipeline.rs index d76b0ff431..609bdf9cdf 100644 --- a/sdk/core/typespec_client_core/src/http/pipeline.rs +++ b/sdk/core/typespec_client_core/src/http/pipeline.rs @@ -73,7 +73,10 @@ impl Pipeline { let pipeline_options = pipeline_options.unwrap_or_default(); - let retry_policy = options.retry.to_policy(pipeline_options.retry_headers); + let retry_policy = options.retry.to_policy( + pipeline_options.retry_headers.clone(), + &pipeline_options.retry_status_codes, + ); pipeline.push(retry_policy); pipeline.extend_from_slice(&per_try_policies); @@ -134,10 +137,8 @@ mod tests { use crate::{ error::{Error, ErrorKind}, http::{ - headers::{Headers, RETRY_AFTER}, - policies::{PolicyResult, RetryHeaders}, - BufResponse, FixedRetryOptions, JsonFormat, Method, Response, RetryOptions, StatusCode, - Transport, + headers::Headers, policies::PolicyResult, BufResponse, FixedRetryOptions, JsonFormat, + Method, Response, RetryOptions, StatusCode, Transport, }, stream::BytesStream, Bytes, @@ -180,12 +181,7 @@ mod tests { transport: Some(Transport::with_policy(Arc::new(Responder {}))), ..Default::default() }; - let pipeline_options = PipelineOptions { - retry_headers: RetryHeaders { - retry_headers: vec![RETRY_AFTER], - }, - }; - let pipeline = Pipeline::new(options, Vec::new(), Vec::new(), Some(pipeline_options)); + let pipeline = Pipeline::new(options, Vec::new(), Vec::new(), None); let mut request = Request::new("http://localhost".parse().unwrap(), Method::Get); let raw_response = pipeline .send(&Context::default(), &mut request, None) diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs b/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs index 7afb35f33c..1441254b04 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs @@ -2,7 +2,10 @@ // Licensed under the MIT License. use super::RetryPolicy; -use crate::{http::policies::RetryHeaders, time::Duration}; +use crate::{ + http::{policies::RetryHeaders, StatusCode}, + time::Duration, +}; /// Retry policy with exponential back-off. /// @@ -18,6 +21,7 @@ pub(crate) struct ExponentialRetryPolicy { max_elapsed: Duration, max_delay: Duration, retry_headers: RetryHeaders, + status_codes: Vec, } impl ExponentialRetryPolicy { @@ -27,6 +31,7 @@ impl ExponentialRetryPolicy { max_elapsed: Duration, max_delay: Duration, retry_headers: RetryHeaders, + status_codes: Vec, ) -> Self { Self { initial_delay: initial_delay.max(Duration::milliseconds(1)), @@ -34,6 +39,7 @@ impl ExponentialRetryPolicy { max_elapsed, max_delay: max_delay.max(Duration::seconds(1)), retry_headers, + status_codes, } } } @@ -47,6 +53,10 @@ impl RetryPolicy for ExponentialRetryPolicy { Some(&self.retry_headers) } + fn get_retry_status_codes(&self) -> &[StatusCode] { + &self.status_codes + } + fn sleep_duration(&self, retry_count: u32) -> Duration { let sleep_ms = self.initial_delay.whole_milliseconds() as u64 * 2u64.pow(retry_count) + u64::from(rand::random::()); @@ -83,6 +93,7 @@ mod tests { RETRY_AFTER, ], }, + vec![], ); let mut elapsed_time = Duration::seconds(0); diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs b/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs index e554a7fca5..4311d82f26 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs @@ -1,7 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -use crate::{http::policies::RetryHeaders, time::Duration}; +use crate::{ + http::{policies::RetryHeaders, StatusCode}, + time::Duration, +}; /// Retry policy with a fixed back-off. /// @@ -15,6 +18,7 @@ pub(crate) struct FixedRetryPolicy { max_retries: u32, max_elapsed: Duration, retry_headers: RetryHeaders, + status_codes: Vec, } impl FixedRetryPolicy { @@ -23,12 +27,14 @@ impl FixedRetryPolicy { max_retries: u32, max_elapsed: Duration, retry_headers: RetryHeaders, + status_codes: Vec, ) -> Self { Self { delay: delay.max(Duration::milliseconds(10)), max_retries, max_elapsed, retry_headers, + status_codes, } } } @@ -42,6 +48,10 @@ impl super::RetryPolicy for FixedRetryPolicy { Some(&self.retry_headers) } + fn get_retry_status_codes(&self) -> &[StatusCode] { + &self.status_codes + } + fn sleep_duration(&self, _retry_count: u32) -> Duration { let sleep_ms = self.delay.whole_milliseconds() as u64 + u64::from(rand::random::()); Duration::milliseconds(sleep_ms as i64) diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs index 5316c2e290..0625ec6511 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs @@ -109,6 +109,16 @@ pub trait RetryPolicy: std::fmt::Debug + Send + Sync { /// If `None` is returned, no headers will be checked. fn get_retry_headers(&self) -> Option<&RetryHeaders>; + /// Get the status codes that should trigger retries. When the returned slice + /// is empty, the policy retries these status codes: + /// - 408 Request Timeout + /// - 429 Too Many Requests + /// - 500 Internal Server Error + /// - 502 Bad Gateway + /// - 503 Service Unavailable + /// - 504 Gateway Timeout + fn get_retry_status_codes(&self) -> &[StatusCode]; + /// Determine how long before the next retry should be attempted. fn sleep_duration(&self, retry_count: u32) -> Duration; /// A Future that will wait until the request can be retried. @@ -127,10 +137,10 @@ pub trait RetryPolicy: std::fmt::Debug + Send + Sync { } } -/// The status codes where a retry should be attempted. +/// Default status codes where a retry should be attempted. /// /// On all other 4xx and 5xx status codes no retry is attempted. -const RETRY_STATUSES: &[StatusCode] = &[ +const DEFAULT_RETRY_STATUSES: &[StatusCode] = &[ StatusCode::RequestTimeout, StatusCode::TooManyRequests, StatusCode::InternalServerError, @@ -168,7 +178,13 @@ where let (last_result, retry_after) = match result { Ok(response) => { let status = response.status(); - if !RETRY_STATUSES.contains(&status) { + let retry_status_codes = self.get_retry_status_codes(); + let retry_status_codes = if retry_status_codes.is_empty() { + DEFAULT_RETRY_STATUSES + } else { + retry_status_codes + }; + if !retry_status_codes.contains(&status) { if status.is_success() { trace!("server returned success status {}", status,); } else { @@ -242,7 +258,8 @@ mod test { use super::*; use crate::http::{ headers::{Headers, RETRY_AFTER}, - BufResponse, Context, FixedRetryOptions, Method, Request, RetryOptions, Url, + BufResponse, Context, ExponentialRetryOptions, FixedRetryOptions, Method, Request, + RetryOptions, Url, }; use ::time::macros::datetime; use std::sync::{Arc, Mutex}; @@ -339,11 +356,11 @@ mod test { max_retries: retries, ..Default::default() }) - .to_policy(retry_headers); + .to_policy(retry_headers, DEFAULT_RETRY_STATUSES); let ctx = Context::new(); let url = Url::parse("http://localhost").unwrap(); - for &status in RETRY_STATUSES { + for &status in DEFAULT_RETRY_STATUSES { let mut request = Request::new(url.clone(), Method::Get); let count = Arc::new(Mutex::new(0)); let mock = StatusResponder { @@ -386,4 +403,113 @@ mod test { "Policy shouldn't retry after receiving a response whose status isn't in RETRY_STATUSES" ); } + + #[tokio::test] + async fn test_custom_status_codes() { + async fn test_custom_retry_statuses(retry_policy: Arc) { + let ctx = Context::new(); + let url = Url::parse("http://localhost").unwrap(); + + let mut request = Request::new(url.clone(), Method::Get); + let count = Arc::new(Mutex::new(0)); + let next = vec![Arc::new(StatusResponder { + request_count: count.clone(), + status: StatusCode::Gone, + }) as Arc]; + + let response = retry_policy + .send(&ctx, &mut request, &next) + .await + .expect("Policy should return a response after exhausting retries"); + + assert_eq!(response.status(), StatusCode::Gone); + assert_eq!( + 2, + *count.lock().unwrap(), + "Policy should retry status in specified list" + ); + + let mut request = Request::new(url.clone(), Method::Get); + let count = Arc::new(Mutex::new(0)); + let next = vec![Arc::new(StatusResponder { + request_count: count.clone(), + status: StatusCode::TooManyRequests, + }) as Arc]; + + let response = retry_policy + .send(&ctx, &mut request, &next) + .await + .expect("Policy should return a response without retrying"); + + assert_eq!(response.status(), StatusCode::TooManyRequests); + assert_eq!( + 1, + *count.lock().unwrap(), + "Policy should not retry status not in custom retry list" + ); + } + + let statuses = vec![StatusCode::Gone]; + + let retry_policy = RetryOptions::fixed(FixedRetryOptions { + delay: Duration::nanoseconds(1), + max_retries: 1, + ..Default::default() + }) + .to_policy(RetryHeaders::default(), &statuses); + test_custom_retry_statuses(retry_policy).await; + + let retry_policy = RetryOptions::exponential(ExponentialRetryOptions { + initial_delay: Duration::nanoseconds(1), + max_retries: 1, + ..Default::default() + }) + .to_policy(RetryHeaders::default(), &statuses); + test_custom_retry_statuses(retry_policy).await; + } + + #[tokio::test] + async fn test_empty_status_codes_use_default_retry_behavior() { + async fn test_retries_for_default_statuses(retry_policy: Arc) { + let ctx = Context::new(); + let url = Url::parse("http://localhost").unwrap(); + for &status in DEFAULT_RETRY_STATUSES { + let mut request = Request::new(url.clone(), Method::Get); + let count = Arc::new(Mutex::new(0)); + let mock = StatusResponder { + request_count: count.clone(), + status, + }; + let next = vec![Arc::new(mock) as Arc]; + let result = retry_policy + .send(&ctx, &mut request, &next) + .await + .expect("Policy should return after exhausting retries"); + assert_eq!(result.status(), status); + assert_eq!( + 2, + *count.lock().unwrap(), + "Policy should retry {status} when given an empty list of status codes" + ); + } + } + + let empty: &[StatusCode] = &[]; + + let retry_policy = RetryOptions::fixed(FixedRetryOptions { + delay: Duration::nanoseconds(1), + max_retries: 1, + ..Default::default() + }) + .to_policy(RetryHeaders::default(), empty); + test_retries_for_default_statuses(retry_policy).await; + + let retry_policy = RetryOptions::exponential(ExponentialRetryOptions { + initial_delay: Duration::nanoseconds(1), + max_retries: 1, + ..Default::default() + }) + .to_policy(RetryHeaders::default(), empty); + test_retries_for_default_statuses(retry_policy).await; + } } From a06dc712405307b3e61a0b29fc89848e01e78d11 Mon Sep 17 00:00:00 2001 From: Charles Lowell <10964656+chlowell@users.noreply.github.com> Date: Mon, 3 Nov 2025 23:53:59 +0000 Subject: [PATCH 2/5] retry_status_codes --- .../typespec_client_core/src/http/options/retry.rs | 6 +++--- .../src/http/policies/retry/exponential.rs | 10 +++++----- .../src/http/policies/retry/fixed.rs | 10 +++++----- .../src/http/policies/retry/mod.rs | 14 +++++++------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sdk/core/typespec_client_core/src/http/options/retry.rs b/sdk/core/typespec_client_core/src/http/options/retry.rs index 19edaebb07..d43fa83a7d 100644 --- a/sdk/core/typespec_client_core/src/http/options/retry.rs +++ b/sdk/core/typespec_client_core/src/http/options/retry.rs @@ -94,7 +94,7 @@ impl RetryOptions { pub(crate) fn to_policy( &self, retry_headers: RetryHeaders, - status_codes: &[StatusCode], + retry_status_codes: &[StatusCode], ) -> Arc { match &self.mode { RetryMode::Exponential(options) => Arc::new(ExponentialRetryPolicy::new( @@ -103,14 +103,14 @@ impl RetryOptions { options.max_total_elapsed, options.max_delay, retry_headers, - status_codes.to_vec(), + retry_status_codes.to_vec(), )), RetryMode::Fixed(options) => Arc::new(FixedRetryPolicy::new( options.delay, options.max_retries, options.max_total_elapsed, retry_headers, - status_codes.to_vec(), + retry_status_codes.to_vec(), )), RetryMode::Custom(c) => c.clone(), RetryMode::None => Arc::new(NoRetryPolicy::new(retry_headers)), diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs b/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs index 1441254b04..b99fc3ce50 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs @@ -21,7 +21,7 @@ pub(crate) struct ExponentialRetryPolicy { max_elapsed: Duration, max_delay: Duration, retry_headers: RetryHeaders, - status_codes: Vec, + retry_status_codes: Vec, } impl ExponentialRetryPolicy { @@ -31,7 +31,7 @@ impl ExponentialRetryPolicy { max_elapsed: Duration, max_delay: Duration, retry_headers: RetryHeaders, - status_codes: Vec, + retry_status_codes: Vec, ) -> Self { Self { initial_delay: initial_delay.max(Duration::milliseconds(1)), @@ -39,7 +39,7 @@ impl ExponentialRetryPolicy { max_elapsed, max_delay: max_delay.max(Duration::seconds(1)), retry_headers, - status_codes, + retry_status_codes, } } } @@ -53,8 +53,8 @@ impl RetryPolicy for ExponentialRetryPolicy { Some(&self.retry_headers) } - fn get_retry_status_codes(&self) -> &[StatusCode] { - &self.status_codes + fn retry_status_codes(&self) -> &[StatusCode] { + &self.retry_status_codes } fn sleep_duration(&self, retry_count: u32) -> Duration { diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs b/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs index 4311d82f26..4a11e585e4 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs @@ -18,7 +18,7 @@ pub(crate) struct FixedRetryPolicy { max_retries: u32, max_elapsed: Duration, retry_headers: RetryHeaders, - status_codes: Vec, + retry_status_codes: Vec, } impl FixedRetryPolicy { @@ -27,14 +27,14 @@ impl FixedRetryPolicy { max_retries: u32, max_elapsed: Duration, retry_headers: RetryHeaders, - status_codes: Vec, + retry_status_codes: Vec, ) -> Self { Self { delay: delay.max(Duration::milliseconds(10)), max_retries, max_elapsed, retry_headers, - status_codes, + retry_status_codes, } } } @@ -48,8 +48,8 @@ impl super::RetryPolicy for FixedRetryPolicy { Some(&self.retry_headers) } - fn get_retry_status_codes(&self) -> &[StatusCode] { - &self.status_codes + fn retry_status_codes(&self) -> &[StatusCode] { + &self.retry_status_codes } fn sleep_duration(&self, _retry_count: u32) -> Duration { diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs index 0625ec6511..22bf7907ab 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs @@ -117,7 +117,7 @@ pub trait RetryPolicy: std::fmt::Debug + Send + Sync { /// - 502 Bad Gateway /// - 503 Service Unavailable /// - 504 Gateway Timeout - fn get_retry_status_codes(&self) -> &[StatusCode]; + fn retry_status_codes(&self) -> &[StatusCode]; /// Determine how long before the next retry should be attempted. fn sleep_duration(&self, retry_count: u32) -> Duration; @@ -140,7 +140,7 @@ pub trait RetryPolicy: std::fmt::Debug + Send + Sync { /// Default status codes where a retry should be attempted. /// /// On all other 4xx and 5xx status codes no retry is attempted. -const DEFAULT_RETRY_STATUSES: &[StatusCode] = &[ +const DEFAULT_RETRY_STATUS_CODES: &[StatusCode] = &[ StatusCode::RequestTimeout, StatusCode::TooManyRequests, StatusCode::InternalServerError, @@ -178,9 +178,9 @@ where let (last_result, retry_after) = match result { Ok(response) => { let status = response.status(); - let retry_status_codes = self.get_retry_status_codes(); + let retry_status_codes = self.retry_status_codes(); let retry_status_codes = if retry_status_codes.is_empty() { - DEFAULT_RETRY_STATUSES + DEFAULT_RETRY_STATUS_CODES } else { retry_status_codes }; @@ -356,11 +356,11 @@ mod test { max_retries: retries, ..Default::default() }) - .to_policy(retry_headers, DEFAULT_RETRY_STATUSES); + .to_policy(retry_headers, DEFAULT_RETRY_STATUS_CODES); let ctx = Context::new(); let url = Url::parse("http://localhost").unwrap(); - for &status in DEFAULT_RETRY_STATUSES { + for &status in DEFAULT_RETRY_STATUS_CODES { let mut request = Request::new(url.clone(), Method::Get); let count = Arc::new(Mutex::new(0)); let mock = StatusResponder { @@ -473,7 +473,7 @@ mod test { async fn test_retries_for_default_statuses(retry_policy: Arc) { let ctx = Context::new(); let url = Url::parse("http://localhost").unwrap(); - for &status in DEFAULT_RETRY_STATUSES { + for &status in DEFAULT_RETRY_STATUS_CODES { let mut request = Request::new(url.clone(), Method::Get); let count = Arc::new(Mutex::new(0)); let mock = StatusResponder { From 6733d08e7d4d5a300e0cc8da2a6b440efe7f3a7b Mon Sep 17 00:00:00 2001 From: Charles Lowell <10964656+chlowell@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:13:37 +0000 Subject: [PATCH 3/5] get_retry_headers -> retry_headers --- sdk/core/azure_core/CHANGELOG.md | 1 + .../src/http/policies/retry/exponential.rs | 2 +- .../typespec_client_core/src/http/policies/retry/fixed.rs | 2 +- sdk/core/typespec_client_core/src/http/policies/retry/mod.rs | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sdk/core/azure_core/CHANGELOG.md b/sdk/core/azure_core/CHANGELOG.md index b12a9673d6..6f6608ae4f 100644 --- a/sdk/core/azure_core/CHANGELOG.md +++ b/sdk/core/azure_core/CHANGELOG.md @@ -20,6 +20,7 @@ - Removed `ErrorKind::MockFramework`. - Removed `Poller::wait()` function. Call `await` on a `Poller` to wait for it to complete and, upon success, return the final model. - Removed `xml::read_xml_str()`. +- Renamed `RetryPolicy::get_retry_headers()` to `RetryPolicy::retry_headers()` - Renamed `xml::read_xml()` to `xml::from_xml()` congruent with `json::from_json()`. ### Bugs Fixed diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs b/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs index b99fc3ce50..baf30c6d92 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/exponential.rs @@ -49,7 +49,7 @@ impl RetryPolicy for ExponentialRetryPolicy { retry_count >= self.max_retries || time_since_start >= self.max_elapsed } - fn get_retry_headers(&self) -> Option<&RetryHeaders> { + fn retry_headers(&self) -> Option<&RetryHeaders> { Some(&self.retry_headers) } diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs b/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs index 4a11e585e4..d9b54374de 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs @@ -44,7 +44,7 @@ impl super::RetryPolicy for FixedRetryPolicy { retry_count >= self.max_retries || time_since_start >= self.max_elapsed } - fn get_retry_headers(&self) -> Option<&RetryHeaders> { + fn retry_headers(&self) -> Option<&RetryHeaders> { Some(&self.retry_headers) } diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs index 22bf7907ab..4f676d3911 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs @@ -107,7 +107,7 @@ pub trait RetryPolicy: std::fmt::Debug + Send + Sync { /// Get the headers that may indicate how long to wait before retrying. /// If `None` is returned, no headers will be checked. - fn get_retry_headers(&self) -> Option<&RetryHeaders>; + fn retry_headers(&self) -> Option<&RetryHeaders>; /// Get the status codes that should trigger retries. When the returned slice /// is empty, the policy retries these status codes: @@ -196,7 +196,7 @@ where return Ok(response); } - let retry_headers = self.get_retry_headers(); + let retry_headers = self.retry_headers(); // For a 429 response (TooManyRequests) or 503 (ServiceUnavailable), // use any "retry-after" headers returned by the server to determine how long to wait before retrying. // https://learn.microsoft.com/en-us/azure/architecture/best-practices/retry-service-specific#retry-usage-guidance From 0d50749fd3d3ca68a5cfb7f4015e908413085d70 Mon Sep 17 00:00:00 2001 From: Charles Lowell <10964656+chlowell@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:15:00 +0000 Subject: [PATCH 4/5] concision --- .../src/http/policies/retry/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs index 4f676d3911..8dc88456f6 100644 --- a/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs +++ b/sdk/core/typespec_client_core/src/http/policies/retry/mod.rs @@ -178,12 +178,10 @@ where let (last_result, retry_after) = match result { Ok(response) => { let status = response.status(); - let retry_status_codes = self.retry_status_codes(); - let retry_status_codes = if retry_status_codes.is_empty() { - DEFAULT_RETRY_STATUS_CODES - } else { - retry_status_codes - }; + let mut retry_status_codes = self.retry_status_codes(); + if retry_status_codes.is_empty() { + retry_status_codes = DEFAULT_RETRY_STATUS_CODES; + } if !retry_status_codes.contains(&status) { if status.is_success() { trace!("server returned success status {}", status,); From 6b48f0a5836c911001fbbe2784cf916ddc04488a Mon Sep 17 00:00:00 2001 From: Charles Lowell <10964656+chlowell@users.noreply.github.com> Date: Tue, 4 Nov 2025 16:04:07 +0000 Subject: [PATCH 5/5] fix doc link --- sdk/core/typespec_client_core/src/http/options/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/core/typespec_client_core/src/http/options/mod.rs b/sdk/core/typespec_client_core/src/http/options/mod.rs index 2ec0183819..786410a4c9 100644 --- a/sdk/core/typespec_client_core/src/http/options/mod.rs +++ b/sdk/core/typespec_client_core/src/http/options/mod.rs @@ -71,7 +71,7 @@ pub struct PipelineOptions { /// field doesn't apply to custom retry policies. /// /// When empty, the default retry status codes are used as - /// described by [`crate::http::policies::RetryPolicy::get_retry_status_codes`]. + /// described by [`crate::http::policies::RetryPolicy::retry_status_codes`]. pub retry_status_codes: Vec, }