-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[core-rest-pipeline] Idea for improving the tokenCycler #15120
[core-rest-pipeline] Idea for improving the tokenCycler #15120
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 I like the idea of taking the token cycler and making a robust abstraction out of it that can be used in many different ways. I have a few comments/concerns about the proposed changes, and at a very high level I think that if we want to make this a general purpose abstraction, that we would want to re-think a few aspects of the design.
sdk/core/core-rest-pipeline/src/policies/bearerTokenAuthenticationPolicy.ts
Show resolved
Hide resolved
|
||
while (token === null) { | ||
while (result === null) { |
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.
The issue I have with this is that it's still particular to the contract of getToken
in core-auth. You wouldn't be able to use this abstraction with something that doesn't return null
as a failure mode. The way this reads to me is "retry every X milliseconds as long as this function is returning null," and then in the inner function we catch errors and return them as null to retry, but that might not always be safe to do in the general case.
If we want to do this refactor with the intention of making this cycler abstraction easier to use with other types of functions, then I think we have to re-think the failure modes to come up with something truly generic. For example, what if the retryUntilTimeout
function accepts as a parameter a predicate that can be used to determine whether an Error can be retried or should be treated as fatal?
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 that the failure modes are an issue on themselves and that null as a failure mode is not generic, but null as a failure mode is easy for two reasons:
- Has way less overhead.
- It's as clear as possible on the type that uses null as the failure mode. It has been clear enough for us to use it in the TokenCredential, for example 🤔
As an alternative to null as a failure mode, what would be better while still not make it much more complicated?
} | ||
|
||
return finalToken; | ||
async function tryUntilTimeout<T>( |
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.
To me the names tryUntilTimeout
and retryUntilTimeout
mean the same thing. This function is specifically made to be part of the inner loop of retryUntilTimeout
, and I think it has limited utility on its own.
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.
Inside of retryUntilTimeout I think it adds too much complexity for one function. The name could be better though. This could become something like "run silently unless a condition is met", and receive a condition instead of a timeout, which would be generic.
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 just think it's a very particular function. "tryOnceAndThrowIfTimeoutExpired"... It only makes sense to be used with retryUntilTimeout
, which still parses in my brain as meaning the exact same thing as tryUntilTimeout
. Maybe this function could simply be called tryOnce
.
I generally like the idea of accepting a predicate representing the error condition instead of checking the date, but like I mentioned in the other comment, I'm skeptical that this makes much sense to use with other "refreshable things" as long as | null
is baked so deeply in. That feels like a leaky abstraction where things would start wanting to return null as a failure mode just for the sake of fitting into that abstraction, even if it's more natural to reject/call a handler, etc.
It might also be possible to use some clever promise chains to eliminate this secondary function entirely.
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.
Oh I see! I like that. Alright, let's come back to this later when we have more time 👍
…okenCyclerImprovementIdea
Related #15678 |
Mitryakh/network march (Azure#15709) * Adds base for updating Microsoft.Network from version stable/2021-02-01 to version 2021-03-01 * Updates readme * Updates API version in new specs and examples * Add new parameter to enable/disable BGP route translation for NAT VirtualWan VpnGateway (Azure#14462) * Adding Bastion Host Configuration Features (Azure#14442) Co-authored-by: Abhishek Shah <shabhis@microsoft.com> * Add PL ASG (Azure#14620) * Add PL ASG * Prettier * [Private Link] Private Endpoint Ipconfigurations swagger for 2021-03-01 (Azure#14662) * Ipconfigurations swagger * Ran prettier check * fixing conflicting files * fixing lint * Fixing linter diff * Lint diff * resolving comments * fixing conflict * Fioxing * running prettier * Fixing linter comment Co-authored-by: Shane Baden <shbaden@microsoft.com> * Add missing properties of ServiceEndpointPolicy (Azure#14948) * Add missing 'type' and 'serviceAlias' for ServiceEndpointPolicy related API response * Add missing 'contextualServiceEndpointPolicies' * fix bug * fix type * Add missing properties to ServiceEndpointPolicy * Revert "fix type" This reverts commit 3a49beb66d9bbb288fa0d3baaeaf5aaf2bbc6ee9. * Revert "fix bug" This reverts commit a4fff4ae925b01ed0cfb07b1594fb95e2c6649c7. * Revert "Add missing 'contextualServiceEndpointPolicies'" This reverts commit ccf19167abc61b90bce6b5204dc3b2a64fdf4ca4. * Revert "Add missing 'type' and 'serviceAlias' for ServiceEndpointPolicy related API response" This reverts commit e532cc1118241a74902e4362c32c25c11a764933. Co-authored-by: Xu Wang <wax@microsoft.com> * add new service tag details api (Azure#14958) * add new service tag details api * prettier check fixes * fixing lint issue, additional properties issue * Add Load distribution policy and global configuration to AppGW (Azure#14790) * add Load distribution policy and global configuration to Application Gateway resource * prettify * remove provisioning state * add public ssh key to network virtual appliance (Azure#14988) * Changes needed for BgpEndpoint (Azure#14800) * changes needed for BgpEndpoint * prettier check * model validation fix * fix description * update again * Multi QoS support for DSCP configuration (Azure#15120) * Updating the DSCP jsons to reflect the multi-qos support * Adding support to multi-qos * adding the type object to NrpQos * fixing the prettier removing my update to the settings * fixing the missing type object error. seeing if this also fixes the additional attributes exception * fixing the prettier exception * almost forgot this, it was refactor from NrpQos to QosDefinition. NRPQos is already being used in Networking repo * copying what I did with my other objects * names didn't match with what I have in NRP's src * forgot to update the examples with the updates in the specification. updating it * fixing the merge exceptions * Add SQL Setting to Firewall Policy (Azure#15110) * Add SQL Setting to Firewall Policy * fix lint check except for object type * resolve linter error * network: fix newly added targets field to an array and missing sub-resource properties in applicationGateways.json (Azure#15318) * fix: change target to an array and add subresource properties * fix target examples * Support to update tags for BastionHost resource (Azure#15446) * Initial commit * Validation fixes * Update bastionHost.json Co-authored-by: Abhishek Shah <shabhis@microsoft.com> * Azure FW - Explicit Proxy feature swagger change (Azure#15017) * explicit proxy swagger change * prettier check fix * lint check * prettier fix * revert unnecessary file change * Add kind to virtual hub (Azure#15562) * Adding customnetworkinterfacename attribute to Private Endpoint (Azure#15574) Co-authored-by: Shane Baden <shbaden@microsoft.com> * Added 3 new properties to InboundNatRule resource (Azure#15611) * Added the missins properties to fix the change breaking update (Azure#15732) Co-authored-by: Nilambari <nilamd@microsoft.com> Co-authored-by: Abhishek Shah <shah.abhi7860@gmail.com> Co-authored-by: Abhishek Shah <shabhis@microsoft.com> Co-authored-by: Yang Shi <yangshi93@gmail.com> Co-authored-by: Shane Baden <naruto.shane@gmail.com> Co-authored-by: Shane Baden <shbaden@microsoft.com> Co-authored-by: Xu Wang <wangxu724@gmail.com> Co-authored-by: Xu Wang <wax@microsoft.com> Co-authored-by: guptas14 <71726901+guptas14@users.noreply.github.com> Co-authored-by: Akshay Gupta <aksgupta@microsoft.com> Co-authored-by: litchiyangMSFT <64560090+litchiyangMSFT@users.noreply.github.com> Co-authored-by: Ritvika Reddy Nagula <rinagula@microsoft.com> Co-authored-by: David Velasco <davelasc@microsoft.com> Co-authored-by: Jiejiong Wu <b564518128@users.noreply.github.com> Co-authored-by: tinawu6 <78238424+tinawu6@users.noreply.github.com> Co-authored-by: irrogozh <irrogozh@microsoft.com>
Hi @sadasant. Thank you for your interest in helping to improve the Azure SDK experience and for your contribution. We've noticed that there hasn't been recent engagement on this pull request. If this is still an active work stream, please let us know by pushing some changes or leaving a comment. Otherwise, we'll close this out in 7 days. |
This PR aims to do small improvements to the tokenCycler. The idea is that we could pick up the pace to do small improvements like this over time. Small refactorings like this should not change the behavior of our products, and can help us continue to improve how we express ideas as we spend more time working with them.
The
tokenCycler
was originally introduced to fix a bug in the@azure/core-http
package. This package reached GA a while ago and since then it had some crucial components that had to be essentially replaced by thetokenCycler
(they weren't publicly replaced, but internally they were replaced). As we wanted to fix the issue without introducing more public surface complexity, thetokenCycler
became a bit its own ecosystem: No changes to the public API, and internally no reliance on existing APIs.Later on we copied the cycler to core-rest-pipeline, and later as we introduced the challenge callbacks, it was necessary to expose some part of the cycler. Since the cycler exposes a
getToken
function (an async function that can receive scopes andgetTokenOptions
and eventually can return a token), this function became exposed to SDK client developers if they wanted to use the bearerTokenChallengePolicy. This public side of the cycler is very small, and I believe it is essentially perfect. It can't be made simpler, as it's a function that creates agetToken
function.Internally, the cycler has to deal with complexity related to:
Some of these ideas could be eventually useful for other work we may do in the SDK. For now though, I believe doing a minimal set of changes to abstract away some of the functionality will reduce the complexity of the cycler by reducing the variable behavior. Business logic anywhere tends to feel like "this is just how it needs to be" (and thus may discourage changes), so as part of this PR, I'm attempting to make some of the functions the cycler uses more like universal utilities and less like subjective, variable business logic.
This PR:
tryGetAccessToken
inside the cycler'sbeginRefresh
function with a generictryUntilTimeout<T>
which calls to any asyncFn until a given timeout is reached.beginRefresh
function with a genericretryUntilTimeout<T>
which retries an asynchronous function as often as the provided interval milliseconds, until the provided Unix date timeout is reached.cycler
object tocyclerState
, as this object represents the most stateful elements of the cycler.Reviews appreciated 🙇♂️🌞