Skip to content

Commit d2e4644

Browse files
committed
Change how pipelines are created
Also introduces base ClientOptions, which all our other SDKs have.
1 parent a0384e9 commit d2e4644

File tree

5 files changed

+96
-80
lines changed

5 files changed

+96
-80
lines changed

sdk/core/src/client_options.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::policies::{Policy, TelemetryOptions};
2+
use std::sync::Arc;
3+
4+
/// Options passed clients to customer policies, telemetry, etc.
5+
#[derive(Clone, Debug, Default)]
6+
pub struct ClientOptions {
7+
// TODO: Expose retry options and transport overrides.
8+
pub per_call_policies: Vec<Arc<dyn Policy>>,
9+
pub per_retry_policies: Vec<Arc<dyn Policy>>,
10+
11+
pub telemetry: TelemetryOptions,
12+
}

sdk/core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ extern crate serde_derive;
1010
mod macros;
1111

1212
mod bytes_stream;
13+
pub mod client_options;
1314
mod context;
1415
pub mod errors;
1516
pub mod headers;
@@ -35,6 +36,7 @@ use std::fmt::Debug;
3536
use uuid::Uuid;
3637

3738
pub use bytes_stream::*;
39+
pub use client_options::ClientOptions;
3840
pub use context::Context;
3941
pub use headers::AddAsHeader;
4042
pub use http_client::{to_json, HttpClient};

sdk/core/src/pipeline.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
use crate::policies::{Policy, PolicyResult, TelemetryPolicy};
2-
use crate::{Context, Request, Response};
2+
use crate::{ClientOptions, Context, Request, Response};
33
use std::sync::Arc;
44

55
/// Execution pipeline.
66
///
77
/// A pipeline follows a precise flow:
88
///
9-
/// 1. Per call policies are executed. Per call policies can fail and bail out of the pipeline
9+
/// 1. Client library-specified per-call policies are executed. Per-call policies can fail and bail out of the pipeline
1010
/// immediately.
11-
/// 2. Retry policy. It allows to re-execute the following policies.
12-
/// 3. Per retry policies. Per retry polices are always executed at least once but are re-executed
11+
/// 2. User-specified per-call policies are executed.
12+
/// 3. Telemetry policy.
13+
/// 4. Retry policy. It allows to re-execute the following policies.
14+
/// 5. Client library-specified per-retry policies. Per-retry polices are always executed at least once but are re-executed
1315
/// in case of retries.
14-
/// 4. Transport policy. Transport policy is always the last policy and is the policy that
16+
/// 6. User-specified per-retry policies are executed.
17+
/// 7. Transport policy. Transport policy is always the last policy and is the policy that
1518
/// actually constructs the `Response` to be passed up the pipeline.
1619
///
1720
/// A pipeline is immutable. In other words a policy can either succeed and call the following
@@ -24,21 +27,29 @@ pub struct Pipeline {
2427
}
2528

2629
impl Pipeline {
30+
/// Creates a new pipeline given the client library crate name and version,
31+
/// alone with user-specified and client library-specified policies.
32+
///
33+
/// Crates can simply pass `option_env!("CARGO_PKG_NAME")` and `option_env!("CARGO_PKG_VERSION")` for the
34+
/// `crate_name` and `crate_version` arguments respectively.
2735
pub fn new(
36+
crate_name: Option<&'static str>,
37+
crate_version: Option<&'static str>,
38+
options: &ClientOptions,
2839
per_call_policies: Vec<Arc<dyn Policy>>,
2940
retry: Arc<dyn Policy>,
3041
per_retry_policies: Vec<Arc<dyn Policy>>,
3142
transport_policy: Arc<dyn Policy>,
3243
) -> Self {
3344
let mut pipeline: Vec<Arc<dyn Policy>> =
34-
Vec::with_capacity(per_call_policies.len() + per_retry_policies.len() + 3);
35-
36-
// TODO: Create pipeline from ClientOptions which should contain user-specified policies + client-added policies.
37-
pipeline.push(Arc::new(TelemetryPolicy::default()));
45+
Vec::with_capacity(options.per_call_policies.len() + per_call_policies.len() + options.per_retry_policies.len() + per_retry_policies.len() + 3);
3846

3947
pipeline.extend_from_slice(&per_call_policies);
48+
pipeline.extend_from_slice(&options.per_call_policies);
49+
pipeline.push(Arc::new(TelemetryPolicy::new(crate_name, crate_version, &options.telemetry)));
4050
pipeline.push(retry);
4151
pipeline.extend_from_slice(&per_retry_policies);
52+
pipeline.extend_from_slice(&options.per_retry_policies);
4253
pipeline.push(transport_policy);
4354

4455
Self { pipeline }

sdk/core/src/policies/telemetry_policy.rs

Lines changed: 56 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,52 @@ use std::sync::Arc;
77

88
#[derive(Clone, Debug, Default)]
99
pub struct TelemetryOptions {
10-
application_id: Option<String>,
11-
}
12-
13-
impl TelemetryOptions {
14-
pub fn new(application_id: Option<String>) -> Self {
15-
Self { application_id }
16-
}
10+
pub application_id: Option<String>,
1711
}
1812

1913
#[derive(Clone, Debug)]
2014
pub struct TelemetryPolicy {
2115
header: String,
2216
}
2317

24-
impl TelemetryPolicy {
25-
pub fn new(options: TelemetryOptions) -> Self {
26-
Self::with_environment::<Env>(options)
18+
/// Sets the User-Agent header with useful information in a typical format for Azure SDKs.
19+
///
20+
/// Client libraries should create a `TelemetryPolicy` using `option_env!()` like so:
21+
/// ```
22+
/// use azure_core::policies::{TelemetryOptions, TelemetryPolicy};
23+
/// let policy = TelemetryPolicy::new(option_env!("CARGO_PKG_NAME"), option_env!("CARGO_PKG_VERSION"), &TelemetryOptions::default());
24+
/// ```
25+
impl<'a> TelemetryPolicy {
26+
pub fn new(
27+
crate_name: Option<&'a str>,
28+
crate_version: Option<&'a str>,
29+
options: &TelemetryOptions,
30+
) -> Self {
31+
Self::new_with_rustc_version(
32+
crate_name,
33+
crate_version,
34+
option_env!("AZSDK_RUSTC_VERSION"),
35+
options,
36+
)
2737
}
2838

29-
fn with_environment<T: Environment>(options: TelemetryOptions) -> Self {
39+
fn new_with_rustc_version(
40+
crate_name: Option<&'a str>,
41+
crate_version: Option<&'a str>,
42+
rustc_version: Option<&'static str>,
43+
options: &TelemetryOptions,
44+
) -> Self {
3045
const UNKNOWN: &'static str = "unknown";
31-
let crate_name = T::crate_name().unwrap_or(UNKNOWN);
32-
let crate_version = T::crate_version().unwrap_or(UNKNOWN);
33-
let rustc_version = T::rustc_version().unwrap_or(UNKNOWN);
46+
let mut crate_name = crate_name.unwrap_or(UNKNOWN);
47+
let crate_version = crate_version.unwrap_or(UNKNOWN);
48+
let rustc_version = rustc_version.unwrap_or(UNKNOWN);
3449
let platform_info = format!("({}; {}; {})", rustc_version, OS, ARCH,);
35-
let header = match options.application_id {
50+
51+
if let Some(name) = crate_name.strip_prefix("azure_") {
52+
crate_name = name;
53+
}
54+
55+
let header = match &options.application_id {
3656
Some(application_id) => format!(
3757
"{} azsdk-rust-{}/{} {}",
3858
application_id, crate_name, crate_version, platform_info
@@ -47,29 +67,6 @@ impl TelemetryPolicy {
4767
}
4868
}
4969

50-
impl Default for TelemetryPolicy {
51-
fn default() -> Self {
52-
TelemetryPolicy::new(TelemetryOptions::default())
53-
}
54-
}
55-
56-
trait Environment {
57-
fn crate_name() -> Option<&'static str> {
58-
option_env!("CARGO_PKG_NAME")
59-
}
60-
61-
fn crate_version() -> Option<&'static str> {
62-
option_env!("CARGO_PKG_VERSION")
63-
}
64-
65-
fn rustc_version() -> Option<&'static str> {
66-
option_env!("AZSDK_RUSTC_VERSION")
67-
}
68-
}
69-
70-
struct Env;
71-
impl Environment for Env {}
72-
7370
#[async_trait::async_trait]
7471
impl Policy for TelemetryPolicy {
7572
async fn send(
@@ -90,54 +87,42 @@ impl Policy for TelemetryPolicy {
9087
mod test {
9188
use super::*;
9289

93-
// tests assume cargo + rustc
94-
const CRATE_NAME: &'static str = env!("CARGO_PKG_NAME");
95-
const CRATE_VERSION: &'static str = env!("CARGO_PKG_VERSION");
96-
const RUSTC_VERSION: &'static str = env!("AZSDK_RUSTC_VERSION");
97-
98-
struct EmptyEnv;
99-
impl Environment for EmptyEnv {
100-
fn crate_name() -> Option<&'static str> {
101-
None
102-
}
103-
104-
fn crate_version() -> Option<&'static str> {
105-
None
106-
}
107-
108-
fn rustc_version() -> Option<&'static str> {
109-
None
110-
}
111-
}
112-
11390
#[test]
114-
fn test_default() {
115-
let policy = TelemetryPolicy::default();
91+
fn test_without_application_id() {
92+
let policy = TelemetryPolicy::new_with_rustc_version(
93+
Some("azure_test"), // Tests that "azure_" is removed.
94+
Some("1.2.3"),
95+
Some("4.5.6"),
96+
&TelemetryOptions::default(),
97+
);
11698
assert_eq!(
11799
policy.header,
118-
format!(
119-
"azsdk-rust-{}/{} ({}; {}; {})",
120-
CRATE_NAME, CRATE_VERSION, RUSTC_VERSION, OS, ARCH
121-
)
100+
format!("azsdk-rust-test/1.2.3 (4.5.6; {}; {})", OS, ARCH)
122101
);
123102
}
124103

125104
#[test]
126105
fn test_with_application_id() {
127-
let options = TelemetryOptions::new(Some("test".to_string()));
128-
let policy = TelemetryPolicy::new(options);
106+
let options = TelemetryOptions {
107+
application_id: Some("my_app".to_string()),
108+
};
109+
let policy = TelemetryPolicy::new_with_rustc_version(
110+
Some("test"),
111+
Some("1.2.3"),
112+
Some("4.5.6"),
113+
&options,
114+
);
129115
assert_eq!(
130116
policy.header,
131-
format!(
132-
"test azsdk-rust-{}/{} ({}; {}; {})",
133-
CRATE_NAME, CRATE_VERSION, RUSTC_VERSION, OS, ARCH
134-
)
117+
format!("my_app azsdk-rust-test/1.2.3 (4.5.6; {}; {})", OS, ARCH)
135118
);
136119
}
137120

138121
#[test]
139122
fn test_missing_env() {
140-
let policy = TelemetryPolicy::with_environment::<EmptyEnv>(TelemetryOptions::default());
123+
// Would simulate if option_env!("CARGO_PKG_NAME"), for example, returned None.
124+
let policy =
125+
TelemetryPolicy::new_with_rustc_version(None, None, None, &TelemetryOptions::default());
141126
assert_eq!(
142127
policy.header,
143128
format!("azsdk-rust-unknown/unknown (unknown; {}; {})", OS, ARCH)

sdk/cosmos/src/clients/cosmos_client.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::resources::ResourceType;
44
use crate::{headers::*, CosmosError};
55
use crate::{requests, ReadonlyString};
66

7+
use azure_core::client_options::ClientOptions;
78
use azure_core::pipeline::Pipeline;
89
use azure_core::policies::{LinearRetryPolicy, Policy, TransportOptions, TransportPolicy};
910
use azure_core::HttpClient;
@@ -37,6 +38,7 @@ pub struct CosmosClient {
3738
}
3839
/// TODO
3940
pub struct CosmosOptions {
41+
options: ClientOptions,
4042
retry: Arc<dyn Policy>,
4143
transport: TransportOptions,
4244
}
@@ -45,6 +47,7 @@ impl CosmosOptions {
4547
/// TODO
4648
pub fn with_client(client: Arc<dyn HttpClient>) -> Self {
4749
Self {
50+
options: ClientOptions::default(),
4851
retry: Arc::new(LinearRetryPolicy::default()), // this defaults to linear backoff
4952
transport: TransportOptions::new(client),
5053
}
@@ -126,6 +129,9 @@ impl CosmosClient {
126129
let transport_policy = TransportPolicy::new(options.transport);
127130

128131
let pipeline = Pipeline::new(
132+
option_env!("CARGO_PKG_NAME"),
133+
option_env!("CARGO_PKG_VERSION"),
134+
&options.options,
129135
per_call_policies,
130136
options.retry,
131137
per_retry_policies,

0 commit comments

Comments
 (0)