perf: cache Azure CLI Graph token across publish command Graph API calls#267
Merged
sellakumaran merged 3 commits intomicrosoft:mainfrom Feb 17, 2026
Merged
Conversation
Add in-memory token caching to GraphApiService.EnsureGraphHeadersAsync() for the Azure CLI code path. Previously, every Graph API call spawned two 'az' subprocesses (account show + get-access-token), resulting in ~22 subprocess spawns per publish command. With caching, the token is acquired once and reused for 5 minutes. Also eliminate redundant service principal lookups in PublishHelpers.CheckMosPrerequisitesAsync() - Check 3 (admin consent verification) previously re-looked up the same 3 resource app SP IDs that Check 1 already found. Now uses a dictionary to pass SP IDs from Check 1 to Check 3. Net result: ~22 subprocess spawns reduced to 2 (91% reduction). Fixes microsoft#265
Contributor
There was a problem hiding this comment.
Pull request overview
Improves a365 publish performance by avoiding repeated Azure CLI (az) subprocess token acquisitions for Graph API calls, and by reusing previously resolved service principal IDs during MOS prerequisites checks.
Changes:
- Add an in-memory, tenant-aware Azure CLI Graph token cache (5-minute TTL) in
GraphApiService.EnsureGraphHeadersAsync(). - Eliminate redundant service principal lookups in
PublishHelpers.CheckMosPrerequisitesAsync()by caching SP object IDs from the initial verification step. - Add unit tests validating token reuse behavior across multiple Graph calls.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs | New tests covering Azure CLI token cache behavior across Graph GET/POST calls and tenants. |
| src/Microsoft.Agents.A365.DevTools.Cli/Services/GraphApiService.cs | Adds tenant-aware in-memory caching for Azure CLI Graph tokens in EnsureGraphHeadersAsync(). |
| src/Microsoft.Agents.A365.DevTools.Cli/Helpers/PublishHelpers.cs | Reuses cached resource SP IDs to avoid duplicate Graph lookups during MOS prerequisites checks. |
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Outdated
Show resolved
Hide resolved
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Outdated
Show resolved
Hide resolved
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Outdated
Show resolved
Hide resolved
Applies code review improvements from pr-267-review.yaml:
- CR-267-001 (MEDIUM): Add cache expiry test
* Added internal property CachedAzCliTokenExpiry to GraphApiService for testability
* Added test GraphGetAsync_ExpiredCache_AcquiresNewToken to validate expired cache behavior
- CR-267-002 (MEDIUM): Clear cache on token acquisition failure
* Added cache clearing logic (_cachedAzCliToken, _cachedAzCliTenantId, _cachedAzCliTokenExpiry)
when GetGraphAccessTokenAsync returns null/empty to ensure clean state on failure
- CR-267-003 (LOW): HttpResponseMessage disposal verified
* Verified TestHttpMessageHandler.Dispose() properly disposes queued responses (no changes needed)
- CR-267-004 (LOW): Cache duration constant placement
* Kept AzCliTokenCacheDuration in GraphApiService as internal constant (no changes needed per review)
- CR-267-005 (INFO): Improve log message clarity
* Updated PublishHelpers.cs Check 3 log from LogDebug "configuration needed" to
LogWarning "unexpected - should have been cached by Check 1" to indicate unexpected condition
All tests passing: 954 passed (including new cache expiry test), 0 failed.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…e tests Fixes inline review comments from GitHub Copilot: 1. HttpResponseMessage disposal (Comments on lines 61, 93): - Wrapped all tests in try-finally blocks to ensure TestHttpMessageHandler.Dispose() is called - This ensures queued HttpResponseMessage instances are properly disposed after each test - Prevents resource leaks during test execution 2. Missing assertion for subprocess reduction (Comment on line 77): - Added assertion to verify 'az account show' is called exactly once - This validates the full subprocess reduction claim (not just get-access-token) - Tests now verify both account show and get-access-token call counts All 5 tests passing with proper resource cleanup. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
sellakumaran
approved these changes
Feb 17, 2026
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Show resolved
Hide resolved
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Show resolved
Hide resolved
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Show resolved
Hide resolved
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/GraphApiServiceTokenCacheTests.cs
Show resolved
Hide resolved
ajmfehr
approved these changes
Feb 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Optimizes the publish command by caching Azure CLI Graph tokens in memory and eliminating redundant service principal lookups.
Fixes #265
Problem
Every Graph API call in the publish command spawns two
azsubprocesses (az account show+az account get-access-token). A typical publish with MOS prerequisites check triggers ~11 Graph API calls = ~22 subprocess spawns, adding ~45-60 seconds of overhead.Additionally,
CheckMosPrerequisitesAsyncinPublishHelpers.csperforms redundant service principal lookups: Check 3 (admin consent verification) re-looks up the same 3 resource app SP IDs that Check 1 (SP verification) already found.Changes
1. Token caching in
GraphApiService.EnsureGraphHeadersAsync()_cachedAzCliToken,_cachedAzCliTenantId,_cachedAzCliTokenExpiry2. Redundant SP lookup elimination in
PublishHelpers.CheckMosPrerequisitesAsync()LookupServicePrincipalByAppIdAsyncImpact
azsubprocess spawns per publishCheckMosPrerequisitesAsyncDue Diligence
Security review
HttpClient.DefaultRequestHeaders.Authorization) regardless of cachingConflict analysis (4 open PRs checked)
PublishCommand.csMockToolingServer/Server.csMsalBrowserCredential.cs,Directory.Packages.propsCleanupCommand.cs,EndpointHelper.csThread safety
Cross-platform
DateTimeOffset.UtcNowfor timezone-safe expiryEdge cases considered
CheckServicePrincipalCreationPrivilegesAsyncbypassesEnsureGraphHeadersAsyncand is unaffectedTesting
a365 publish --verboseconfirmed 1x token acquisition + 10x cache hitsBefore (verbose output)
After (verbose output)