-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement timeouts for LazyCachingCredentialsProvider #595
Implement timeouts for LazyCachingCredentialsProvider #595
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall implementation looks good. I think we need to work a bit more about how the cargo features are going to work out.
aws/rust-runtime/aws-auth/Cargo.toml
Outdated
@@ -19,3 +24,4 @@ http = "0.2.3" | |||
test-env-log = { version = "0.2.7", features = ["trace"] } | |||
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread", "test-util"] } | |||
tracing-subscriber = { version = "0.2.16", features = ["fmt"] } | |||
smithy-http = { path = "../../../rust-runtime/smithy-http", features = ["sleep-tokio"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you actually don't want to mention the feature here—mentioning it here makes it a hard dependency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when timeout-tokio is enabled, it will get pulled in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be fine since it's under [dev-dependencies]
.
/// Implementation of [`AsyncSleep`] for Tokio. | ||
#[cfg(feature = "sleep-tokio")] | ||
#[derive(Default)] | ||
pub struct TokioSleep; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[non_exhaustive]
to prevent people from constructing this directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call! Will fix.
use std::pin::Pin; | ||
use std::task::{Context, Poll}; | ||
|
||
#[derive(Debug, Copy, Clone, Eq, PartialEq)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#[non_exhaustive]
@@ -186,8 +202,9 @@ pub mod builder { | |||
); | |||
LazyCachingCredentialsProvider::new( | |||
SystemTimeSource, | |||
self.refresh.expect("refresh provider is required"), | |||
self.refresh_timeout.unwrap_or(DEFAULT_REFRESH_TIMEOUT), | |||
self.sleep.expect("sleep_impl is required"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the tokio feature is enabled, we could consider defaulting to tokio-sleep here
rust-runtime/smithy-http/Cargo.toml
Outdated
@@ -7,6 +7,7 @@ license = "Apache-2.0" | |||
|
|||
[features] | |||
bytestream-util = ["tokio/fs", "tokio-util/io"] | |||
sleep-tokio = ["tokio/time"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we probably don't want this in smithy-http. Also, since this doesn't actually bring in the runtime, this isn't sufficient to actually work.
use std::time::Duration; | ||
|
||
// Re-export AsyncSleep and TokioSleep so that an explicit dependency on smithy-http isn't needed | ||
pub use smithy_http::sleep::AsyncSleep; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth noting, this adds a public API dependency on smithy-http
, so breaking change releases will need to be coordinated.
/// Async trait with a `sleep` function. | ||
pub trait AsyncSleep: Send + Sync { | ||
/// Returns a future that sleeps for the given `duration` of time. | ||
fn sleep(&self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For future compatibility, you may want to consider defining struct Sleep(Pin<Box<...>>)
and Sleep::new(impl Future + Send)
(or whatever). That will give you some wiggle room in the future if you need to change the return type.
pub struct LazyCachingCredentialsProvider { | ||
time: Box<dyn TimeSource>, | ||
sleeper: Box<dyn AsyncSleep>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a hard/fast rule, but based on my observations, usually w/ Rust, *er
tends to be avoided as a suffix.
// it can be used with different async runtimes. The sleep function will be used for timeouts. | ||
// Since we're using Tokio in this example, we use the `TokioSleep` implementation, which | ||
// requires the `timeout-tokio` feature in the `aws-auth` dependency. | ||
.sleeper(TokioSleep::new()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree w/ @rcoh that, in the default case, this should not be specified by the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, test failure is a broken doc link
@@ -202,8 +199,10 @@ pub mod builder { | |||
); | |||
LazyCachingCredentialsProvider::new( | |||
SystemTimeSource, | |||
self.sleep.expect("sleep_impl is required"), | |||
self.loader.expect("loader is required"), | |||
self.sleep.unwrap_or_else(|| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably better to make this a fallible builder rather than hard crashing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this fall under the category of programmer error? Or are you thinking there will be use-cases where sleep
is set programmatically instead of hardcoded?
// requires the `timeout-tokio` feature in the `aws-auth` dependency. | ||
.sleeper(TokioSleep::new()) | ||
.loader(async_provide_credentials_fn(move || { | ||
.load(async_provide_credentials_fn(move || { | ||
let client = client.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe make a separate async fn for this so it's clear you don't have to embed the entire body in the async fn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If taking that approach, it's probably better to implement AsyncProvideCredentials
on a struct instead, because you need a way to bind the STS Client
to the function.
use std::time::Duration; | ||
|
||
/// Async trait with a `sleep` function. | ||
pub trait AsyncSleep: std::fmt::Debug + Send + Sync { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hesitant about this Debug
bound. I would probably drop it, I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @carllerche for your take. I guess the alternative is manually implementing debug for things that contain this type, or leaving it as a generic parameter and deriving debug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reasoning here was that someone would be able to tell which sleep implementation they were using by debug printing it, which would result in TokioSleep
if it were the Tokio implementation provided in this same file. I suspect implementations of this won't have any data associated with them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be consistent w/ all other traits. It isn't unreasonable to require Debug
when dealing mostly w/ trait objects. Most types implement Debug
, so it shouldn't be much of a burden. However, if no other trait extends Debug, I probably wouldn't do it here either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first and only trait in the crate so far, so it will be consistent. This crate is intended to be used to provide async runtime agnostic abstractions, so having Debug
on the traits to be able to tell which concrete implementation is being used is probably valuable, especially since these traits will be used as trait objects.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.