-
Notifications
You must be signed in to change notification settings - Fork 3.2k
[Identity] Add async token method concurrency control #43889
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
base: main
Are you sure you want to change the base?
Conversation
72890fc to
1c2203d
Compare
API Change CheckAPIView identified API level changes in this PR and created the following API reviews |
1c2203d to
efe5b16
Compare
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.
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| try: | ||
| token = await self._request_token( | ||
| *scopes, claims=claims, tenant_id=tenant_id, enable_cae=enable_cae, **kwargs | ||
| ) | ||
| except Exception: # pylint:disable=broad-except | ||
| self._last_request_time = int(time.time()) |
Copilot
AI
Nov 10, 2025
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 _last_request_time update should occur before calling _request_token (on success path) as well, not only in the exception handler. Currently, when _request_token succeeds, _last_request_time is never updated, which could bypass the retry delay check in _should_refresh. This inconsistency means the retry delay only applies after failures, not after successful token requests.
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 want to modify this logic to only set the _last_request_time throttle when a _request_token call fails.
This still prevents rapid retries on failures, without allowing a successful request for one scope to block a necessary refresh for another (which would be the case if we set this on success as well).
sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py
Outdated
Show resolved
Hide resolved
sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py
Outdated
Show resolved
Hide resolved
sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py
Outdated
Show resolved
Hide resolved
sdk/identity/azure-identity/azure/identity/aio/_internal/get_token_mixin.py
Outdated
Show resolved
Hide resolved
Implements per-scope lock mechanism to prevent concurrent token requests for the same token request argument combination, reducing unnecessary network calls and improving performance in high-concurrency async scenarios. Signed-off-by: Paul Van Eck <paulvaneck@microsoft.com>
efe5b16 to
c764476
Compare
| from typing import Type | ||
|
|
||
|
|
||
| def get_running_async_lock_class() -> Type: |
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.
Should we move this into azure-core?
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.
Core does already have a similar function, but it returns a Lock instance instead of a class/type. An instance is fine for most cases where only one lock needs to be instantiated, but in this particular scenario, several locks are instantiated. I only want to check the event loop once to get the class, so I think it's fine to have a separate function here for this purpose.
Motivation
In high-concurrency asynchronous applications, it's common for multiple coroutines to simultaneously request an access token for the same scope (e.g., https://cosmos.azure.com/.default). When a token is expired or not yet cached, this can trigger multiple, identical, and concurrent network requests to Entra ID. This "thundering herd" can put unnecessary load on both the client app and the Entra ID service, and it can also result in redundant network calls when only one is ultimately needed.
Changes
This pull request implements asynchronous locking within the async
GetTokenMixinto ensure that for any given set of token request arguments, only one network request is in-flight at any given time,get_token/get_token_infois called asynchronously, the credential now first checks for an existing lock associated with the specific combination of scopes and token request arguments.Results
Implementation Notes
Supplemental gist: https://gist.github.com/pvaneck/133ab2cc1fe57d4aeb0f31fd00c0a77d