Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/core/azure_core/src/http/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions sdk/core/typespec_client_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion sdk/core/typespec_client_core/src/http/options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<StatusCode>,
}

impl Default for PipelineOptions {
Expand All @@ -73,6 +81,7 @@ impl Default for PipelineOptions {
retry_headers: RetryHeaders {
retry_headers: vec![RETRY_AFTER],
},
retry_status_codes: Vec::new(),
}
}
}
16 changes: 13 additions & 3 deletions sdk/core/typespec_client_core/src/http/options/retry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -87,20 +91,26 @@ impl RetryOptions {
}
}

pub(crate) fn to_policy(&self, retry_headers: RetryHeaders) -> Arc<dyn Policy> {
pub(crate) fn to_policy(
&self,
retry_headers: RetryHeaders,
status_codes: &[StatusCode],
) -> Arc<dyn Policy> {
match &self.mode {
RetryMode::Exponential(options) => Arc::new(ExponentialRetryPolicy::new(
options.initial_delay,
options.max_retries,
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)),
Expand Down
18 changes: 7 additions & 11 deletions sdk/core/typespec_client_core/src/http/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -18,6 +21,7 @@ pub(crate) struct ExponentialRetryPolicy {
max_elapsed: Duration,
max_delay: Duration,
retry_headers: RetryHeaders,
status_codes: Vec<StatusCode>,
}

impl ExponentialRetryPolicy {
Expand All @@ -27,13 +31,15 @@ impl ExponentialRetryPolicy {
max_elapsed: Duration,
max_delay: Duration,
retry_headers: RetryHeaders,
status_codes: Vec<StatusCode>,
) -> Self {
Self {
initial_delay: initial_delay.max(Duration::milliseconds(1)),
max_retries,
max_elapsed,
max_delay: max_delay.max(Duration::seconds(1)),
retry_headers,
status_codes,
}
}
}
Expand All @@ -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::<u8>());
Expand Down Expand Up @@ -83,6 +93,7 @@ mod tests {
RETRY_AFTER,
],
},
vec![],
);

let mut elapsed_time = Duration::seconds(0);
Expand Down
12 changes: 11 additions & 1 deletion sdk/core/typespec_client_core/src/http/policies/retry/fixed.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand All @@ -15,6 +18,7 @@ pub(crate) struct FixedRetryPolicy {
max_retries: u32,
max_elapsed: Duration,
retry_headers: RetryHeaders,
status_codes: Vec<StatusCode>,
}

impl FixedRetryPolicy {
Expand All @@ -23,12 +27,14 @@ impl FixedRetryPolicy {
max_retries: u32,
max_elapsed: Duration,
retry_headers: RetryHeaders,
status_codes: Vec<StatusCode>,
) -> Self {
Self {
delay: delay.max(Duration::milliseconds(10)),
max_retries,
max_elapsed,
retry_headers,
status_codes,
}
}
}
Expand All @@ -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::<u8>());
Duration::milliseconds(sleep_ms as i64)
Expand Down
Loading