Conversation
b8d4051 to
f47c72f
Compare
| class AWS_CORE_API CredentialsRefreshProvider : public AWSCredentialsProvider | ||
| { | ||
| public: | ||
| explicit CredentialsRefreshProvider(std::shared_ptr<CredentialsSource> source); |
There was a problem hiding this comment.
so lets think about this constructor and the new interface CredentialsSource. credentials refresh provider is meant to be like other SDKs where we wrap a existing credentials provider and cache that. there are however several issues with this
CredentialsSource is not a AWSCredentialsProvider
in the default chain we do something like
class chain(): public AWSCredentialsProvider {
public:
chain() {
providers.push_back(std::make_shared<SomeCredentialsProvider>);
}
private:
std::vector<AWSCredentialsProvider> providers
}
now all of our implementations of AWSCredentialsProvider specifically in this example SomeCredentialsProvider how have to implement these functions. and implement a new interface. im not strictly against this we just need to weigh whether we want to do this or not.
this approach has two problems:
double caching/no caching
what about wrapping credentials provider that already cache like all of the CRT credentials providers. you are more or less unwrapping those, and making a parallel caching API which is a lot of surface area. additionally if you remove the caching layer, existing users of the credentials provider now have no caching.
_direct usage of the crednetials provider has no caching
directly constructing a credentials provider has no caching necessarily because only in the chain we wrap it.
before we do this, we need to evaluate how and where this caching will be added, and answer these questions.
There was a problem hiding this comment.
Answered in the comment below
| virtual Aws::Utils::DateTime CurrentTime() const; | ||
|
|
||
| private: | ||
| std::shared_ptr<AWSCredentialsProvider> m_delegate; |
There was a problem hiding this comment.
if CredentialsCachingStateImpl is a unique pointer why is AWSCredentialsProvider a shared?
There was a problem hiding this comment.
Providers are handed around as shared_ptr everywhere: AWSCredentialsProviderChain stores them that way (and keeps a second shared_ptr in m_cachedProvider for the last successful one), and the client constructors and ClientConfiguration take them that way. So a customer wrapping their own provider usually already holds a shared_ptr and may hand the same one to more than one client.
we can make cachingstate a shared pointer but I'm not sure what is the benefit to making it a shared pointer (im not willing to die on this hill tho)
| { | ||
| public: | ||
| explicit CredentialsCachingProvider(std::shared_ptr<AWSCredentialsProvider> delegate); | ||
| ~CredentialsCachingProvider() override; |
There was a problem hiding this comment.
needs final class, or virtual destructor
There was a problem hiding this comment.
changed to a final
| } | ||
| return Aws::Internal::RefreshResult<AWSCredentials>::Fresh(credentials, credentials.GetExpiration()); | ||
| }, | ||
| [this]() { return CurrentTime(); })) |
There was a problem hiding this comment.
So lets start with the objective here which is "i need to mock a clock so i can test a class that is dependent on time". here you added to the public API a overridable API. that is something we do not want to do. it makes consumers pay for the testing mock you added.
There are two options:
- Dont mock it. Why cant the values created in the tests mimic real events. i.e. the return of
GetAWSCredentialsis 100 percent mockable. why isnt the method of the delegate returning credentials with the values instead of injecting time stamps. I really think this is the way we should go, and will need to know a concrete reason why we cant do this, because otherwise we are adding to the public API just for testing. - passing in a
std::functionto the constructor, not a virtual function on the class. This is infact one of the explicit thing from effective c++ that you should not do. Never call virtual functions during
construction or destruction.. theres no reason for this to be virtual, passing it in the constructor as a callback makes more sense.
There was a problem hiding this comment.
Yaa thats bad. Removed this public api
| } | ||
|
|
||
| protected: | ||
| DateTime CurrentTime() const override { return *m_now; } |
There was a problem hiding this comment.
why is this protected, and why is datetime a shared pointer
There was a problem hiding this comment.
Removed this whole class
| NonRecoverable | ||
| }; | ||
|
|
||
| RefreshResult() = default; |
There was a problem hiding this comment.
why is this default constructible, how is it in a valid state after default construction?
There was a problem hiding this comment.
Removed the default construction
| }; | ||
|
|
||
| RefreshResult() = default; | ||
| RefreshResult(Status status, CredentialsT credentials, Aws::Crt::Optional<Aws::Utils::DateTime> expiration, |
There was a problem hiding this comment.
you have three static functions that return three different sets of "valid variants" why is this a public constructor and not a private constructor. that would follow the factory pattern.
There was a problem hiding this comment.
Yup updated as part of the other comment
| }; | ||
|
|
||
| // Advisory window for a given credential lifetime. | ||
| inline std::chrono::milliseconds ComputeAdvisoryWindow(std::chrono::milliseconds lifetime) |
There was a problem hiding this comment.
all of these inlines are public in the header, why are they not private function in the class that uses them, having them as free-floating in the header makes is do anyone including thie header and use them. additioanlly these should likely be local to a cpp.
There was a problem hiding this comment.
Youre right, moving the inline functions to private functions
| { | ||
| if (jitter01 < 0.0) { jitter01 = 0.0; } | ||
| if (jitter01 > 1.0) { jitter01 = 1.0; } | ||
| const int64_t span = hi.count() - lo.count(); |
There was a problem hiding this comment.
what if this is negative?
There was a problem hiding this comment.
ScaleJitter now returns lo when hi <= lo, so an inverted range can't produce a negative duration.
| } | ||
|
|
||
| // Feature gate (dark ship): off unless AWS_NEW_CREDENTIAL_REFRESH_2026 is "true". | ||
| inline bool IsNewCredentialsRefreshEnabled() |
There was a problem hiding this comment.
this function isnt called why is it here?
There was a problem hiding this comment.
this is the gate that gets used later in the wiring PR
| * backoff, a single in-flight fetch, and serving the last-good credentials when a fetch fails. | ||
| * Empty credentials from the wrapped provider mark a failed fetch. | ||
| */ | ||
| class AWS_CORE_API CredentialsCachingProvider : public AWSCredentialsProvider |
There was a problem hiding this comment.
how is this going to work in the SDK. how will it work in the existing deafult chain, and how will existing users who specifically use a credentials provider use this?
There was a problem hiding this comment.
We are adding a cache member CachingCrendialsProvider to providers, and refresh behavior delegates to it
Issue #, if available:
Description of changes:
Add shared credential-refresh lifecycle to AWSCredentialsProvider
Check all that applies:
Check which platforms you have built SDK on to verify the correctness of this PR.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.