8 8 | //! Note: these are the absolute base-level defaults. They may not be the defaults
|
9 9 | //! for _your_ client, since many things can change these defaults on the way to
|
10 10 | //! code generating and constructing a full client.
|
11 11 |
|
12 12 | use crate::client::http::body::content_length_enforcement::EnforceContentLengthRuntimePlugin;
|
13 13 | use crate::client::identity::IdentityCache;
|
14 14 | use crate::client::retries::strategy::standard::TokenBucketProvider;
|
15 15 | use crate::client::retries::strategy::StandardRetryStrategy;
|
16 16 | use crate::client::retries::RetryPartition;
|
17 17 | use aws_smithy_async::rt::sleep::default_async_sleep;
|
18 - | use aws_smithy_async::time::SystemTimeSource;
|
18 + | use aws_smithy_async::time::{SharedTimeSource, SystemTimeSource, TimeSource};
|
19 19 | use aws_smithy_runtime_api::box_error::BoxError;
|
20 20 | use aws_smithy_runtime_api::client::behavior_version::BehaviorVersion;
|
21 21 | use aws_smithy_runtime_api::client::http::SharedHttpClient;
|
22 22 | use aws_smithy_runtime_api::client::runtime_components::{
|
23 23 | RuntimeComponentsBuilder, SharedConfigValidator,
|
24 24 | };
|
25 25 | use aws_smithy_runtime_api::client::runtime_plugin::{
|
26 26 | Order, SharedRuntimePlugin, StaticRuntimePlugin,
|
27 27 | };
|
28 28 | use aws_smithy_runtime_api::client::stalled_stream_protection::StalledStreamProtectionConfig;
|
29 29 | use aws_smithy_runtime_api::shared::IntoShared;
|
30 30 | use aws_smithy_types::config_bag::{ConfigBag, FrozenLayer, Layer};
|
31 31 | use aws_smithy_types::retry::RetryConfig;
|
32 32 | use aws_smithy_types::timeout::TimeoutConfig;
|
33 33 | use std::borrow::Cow;
|
34 34 | use std::time::Duration;
|
35 35 |
|
36 36 | fn default_plugin<CompFn>(name: &'static str, components_fn: CompFn) -> StaticRuntimePlugin
|
37 37 | where
|
38 38 | CompFn: FnOnce(RuntimeComponentsBuilder) -> RuntimeComponentsBuilder,
|
39 39 | {
|
40 40 | StaticRuntimePlugin::new()
|
41 41 | .with_order(Order::Defaults)
|
42 42 | .with_runtime_components((components_fn)(RuntimeComponentsBuilder::new(name)))
|
43 43 | }
|
44 44 |
|
45 45 | fn layer<LayerFn>(name: &'static str, layer_fn: LayerFn) -> FrozenLayer
|
46 46 | where
|
47 47 | LayerFn: FnOnce(&mut Layer),
|
48 48 | {
|
119 119 | pub fn default_time_source_plugin() -> Option<SharedRuntimePlugin> {
|
120 120 | Some(
|
121 121 | default_plugin("default_time_source_plugin", |components| {
|
122 122 | components.with_time_source(Some(SystemTimeSource::new()))
|
123 123 | })
|
124 124 | .into_shared(),
|
125 125 | )
|
126 126 | }
|
127 127 |
|
128 128 | /// Runtime plugin that sets the default retry strategy, config (disabled), and partition.
|
129 + | #[deprecated = "Use default_retry_config_plugin_v2 to get a TokenBucket that respects the user provided TimeSource."]
|
129 130 | pub fn default_retry_config_plugin(
|
130 131 | default_partition_name: impl Into<Cow<'static, str>>,
|
131 132 | ) -> Option<SharedRuntimePlugin> {
|
132 133 | let retry_partition = RetryPartition::new(default_partition_name);
|
133 134 | Some(
|
134 135 | default_plugin("default_retry_config_plugin", |components| {
|
135 136 | components
|
136 137 | .with_retry_strategy(Some(StandardRetryStrategy::new()))
|
137 138 | .with_config_validator(SharedConfigValidator::base_client_config_fn(
|
138 139 | validate_retry_config,
|
139 140 | ))
|
140 - | .with_interceptor(TokenBucketProvider::new(retry_partition.clone()))
|
141 + | .with_interceptor(TokenBucketProvider::new(
|
142 + | retry_partition.clone(),
|
143 + | SharedTimeSource::default(), // Replicates previous behavior
|
144 + | ))
|
145 + | })
|
146 + | .with_config(layer("default_retry_config", |layer| {
|
147 + | layer.store_put(RetryConfig::disabled());
|
148 + | layer.store_put(retry_partition);
|
149 + | }))
|
150 + | .into_shared(),
|
151 + | )
|
152 + | }
|
153 + |
|
154 + | /// Runtime plugin that sets the default retry strategy, config (disabled), and partition.
|
155 + | pub fn default_retry_config_plugin_v2(
|
156 + | default_plugin_params: &DefaultPluginParams,
|
157 + | ) -> Option<SharedRuntimePlugin> {
|
158 + | let retry_partition = RetryPartition::new(
|
159 + | default_plugin_params
|
160 + | .retry_partition_name()
|
161 + | .clone()
|
162 + | .expect("retry_partition_name is required"),
|
163 + | );
|
164 + | Some(
|
165 + | default_plugin("default_retry_config_plugin", |components| {
|
166 + | components
|
167 + | .with_retry_strategy(Some(StandardRetryStrategy::new()))
|
168 + | .with_config_validator(SharedConfigValidator::base_client_config_fn(
|
169 + | validate_retry_config,
|
170 + | ))
|
171 + | .with_interceptor(TokenBucketProvider::new(
|
172 + | retry_partition.clone(),
|
173 + | default_plugin_params
|
174 + | .time_source
|
175 + | .clone()
|
176 + | .unwrap_or_default(),
|
177 + | ))
|
141 178 | })
|
142 179 | .with_config(layer("default_retry_config", |layer| {
|
143 180 | layer.store_put(RetryConfig::disabled());
|
144 181 | layer.store_put(retry_partition);
|
145 182 | }))
|
146 183 | .into_shared(),
|
147 184 | )
|
148 185 | }
|
149 186 |
|
150 187 | fn validate_retry_config(
|
151 188 | components: &RuntimeComponentsBuilder,
|
152 189 | cfg: &ConfigBag,
|
153 190 | ) -> Result<(), BoxError> {
|
154 191 | if let Some(retry_config) = cfg.load::<RetryConfig>() {
|
155 192 | if retry_config.has_retry() && components.sleep_impl().is_none() {
|
156 193 | Err("An async sleep implementation is required for retry to work. Please provide a `sleep_impl` on \
|
157 194 | the config, or disable timeouts.".into())
|
158 195 | } else {
|
159 196 | Ok(())
|
160 197 | }
|
161 198 | } else {
|
162 199 | Err(
|
163 200 | "The default retry config was removed, and no other config was put in its place."
|
164 201 | .into(),
|
165 202 | )
|
166 203 | }
|
167 204 | }
|
168 205 |
|
169 206 | /// Runtime plugin that sets the default timeout config (no timeouts).
|
170 207 | pub fn default_timeout_config_plugin() -> Option<SharedRuntimePlugin> {
|
281 318 | }
|
282 319 |
|
283 320 | /// Arguments for the [`default_plugins`] method.
|
284 321 | ///
|
285 322 | /// This is a struct to enable adding new parameters in the future without breaking the API.
|
286 323 | #[non_exhaustive]
|
287 324 | #[derive(Debug, Default)]
|
288 325 | pub struct DefaultPluginParams {
|
289 326 | retry_partition_name: Option<Cow<'static, str>>,
|
290 327 | behavior_version: Option<BehaviorVersion>,
|
328 + | time_source: Option<SharedTimeSource>,
|
291 329 | }
|
292 330 |
|
293 331 | impl DefaultPluginParams {
|
294 332 | /// Creates a new [`DefaultPluginParams`].
|
295 333 | pub fn new() -> Self {
|
296 334 | Default::default()
|
297 335 | }
|
298 336 |
|
299 337 | /// Sets the retry partition name.
|
300 338 | pub fn with_retry_partition_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
301 339 | self.retry_partition_name = Some(name.into());
|
302 340 | self
|
303 341 | }
|
304 342 |
|
343 + | /// Gets the retry partition name.
|
344 + | pub fn retry_partition_name(&self) -> &Option<Cow<'static, str>> {
|
345 + | &self.retry_partition_name
|
346 + | }
|
347 + |
|
305 348 | /// Sets the behavior major version.
|
306 349 | pub fn with_behavior_version(mut self, version: BehaviorVersion) -> Self {
|
307 350 | self.behavior_version = Some(version);
|
308 351 | self
|
309 352 | }
|
353 + |
|
354 + | /// Gets the behavior major version.
|
355 + | pub fn behavior_version(&self) -> &Option<BehaviorVersion> {
|
356 + | &self.behavior_version
|
357 + | }
|
358 + |
|
359 + | /// Sets the time_source.
|
360 + | pub fn with_time_source(mut self, time_source: impl TimeSource + 'static) -> Self {
|
361 + | self.time_source = Some(SharedTimeSource::new(time_source));
|
362 + | self
|
363 + | }
|
364 + |
|
365 + | /// Gets the time_source.
|
366 + | pub fn time_source(&self) -> &Option<SharedTimeSource> {
|
367 + | &self.time_source
|
368 + | }
|
310 369 | }
|
311 370 |
|
312 371 | /// All default plugins.
|
313 372 | pub fn default_plugins(
|
314 373 | params: DefaultPluginParams,
|
315 374 | ) -> impl IntoIterator<Item = SharedRuntimePlugin> {
|
316 375 | let behavior_version = params
|
317 376 | .behavior_version
|
318 377 | .unwrap_or_else(BehaviorVersion::latest);
|
319 378 |
|
320 379 | [
|
321 380 | default_http_client_plugin_v2(behavior_version),
|
322 381 | default_identity_cache_plugin(),
|
323 - | default_retry_config_plugin(
|
324 - | params
|
325 - | .retry_partition_name
|
326 - | .expect("retry_partition_name is required"),
|
327 - | ),
|
382 + | default_retry_config_plugin_v2(¶ms),
|
328 383 | default_sleep_impl_plugin(),
|
329 384 | default_time_source_plugin(),
|
330 385 | default_timeout_config_plugin(),
|
331 386 | enforce_content_length_runtime_plugin(),
|
332 387 | default_stalled_stream_protection_config_plugin_v2(behavior_version),
|
333 388 | ]
|
334 389 | .into_iter()
|
335 390 | .flatten()
|
336 391 | .collect::<Vec<SharedRuntimePlugin>>()
|
337 392 | }
|