perf(cli): add in-memory caching for redundant TDP reads#2902
Merged
Conversation
Add process-scoped in-memory caches to eliminate redundant TDP network
reads within a single CLI invocation:
- Generic createResourceCache<T>() (clone-on-read/write) as a reusable layer
- App-details cache: fetchAppDetailsV2 is cache-first with a {force} opt-out;
updateAppDetails write-refreshes from its POST response; importAppPackage
invalidates. Collapses ~7-9 reads per `app update` to 1.
- Bot cache: fetchBot and getBotLocation share one GET /botframework/{botId}
via a single readBotResource() classifier (200=tm, 404=azure); mutations
refresh/invalidate. Removes the duplicate spinner/round-trip on app detail.
- Gate the fetchAppDetail spinner to stay silent when both reads are warm.
Includes unit tests (TDD) and a gated live timing integration test
(RUN_INTEGRATION=1).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds process-scoped, in-memory caching for high-frequency TDP read paths in the teams CLI (app details + bot reads), using a small reusable cache helper to reduce redundant network round-trips within a single invocation.
Changes:
- Introduce a generic
createResourceCache<T>()utility (Map-backed, clone-safe get/set/invalidate). - Cache
fetchAppDetailsV2reads with a{ force }bypass; refresh cache onupdateAppDetails; invalidate on package import. - Cache bot read outcomes (200→Teams-managed w/details, 404→Azure), shared by
fetchBotandgetBotLocation; add tests + an opt-in live integration test.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/cli/src/utils/resource-cache.ts | Adds reusable clone-safe, process-scoped cache primitive. |
| packages/cli/src/apps/app-details-cache.ts | App-details cache wrapper + invalidation API. |
| packages/cli/src/apps/bot-cache.ts | Bot read-result cache wrapper shared across call sites. |
| packages/cli/src/apps/api.ts | Makes fetchAppDetailsV2 cache-first w/ { force }; refreshes cache on update. |
| packages/cli/src/apps/tdp.ts | Adds cached bot reader + bot cache refresh/invalidate hooks; invalidates app-details cache on import. |
| packages/cli/src/apps/bot-location.ts | Reuses cached bot reader instead of issuing its own GET. |
| packages/cli/src/apps/home.ts | Avoids spinner noise when required resources are already warm in cache. |
| packages/cli/src/apps/index.ts | Re-exports cache modules. |
| packages/cli/tests/app-details-cache.test.ts | Unit tests for app-details caching/force/invalidate/clone-safety. |
| packages/cli/tests/bot-cache.test.ts | Unit tests for bot caching, shared read, refresh, invalidate, clone-safety. |
| packages/cli/tests/app-details-cache.integration.test.ts | Opt-in live test demonstrating reduced round-trips. |
| packages/cli/tests/update-app-details-bump.test.ts | Ensures cache is cleared between tests to avoid cross-test coupling. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Can we also update our linting rules to include stuff like this? Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
use == null instead Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
… noUnusedLocals lint rule - Fix extra `}` in resource-cache.ts invalidate method introduced by previous autofix commit - Remove unused imports: AppBot (api.ts), fetchApp (bot/get.ts), createTdpBotHandler (update.ts), select and logger (az-prompts.ts) - Add noUnusedLocals: true to tsconfig.json so tsc --noEmit catches unused imports going forward
singhk97
approved these changes
Jun 24, 2026
heyitsaamir
added a commit
that referenced
this pull request
Jul 2, 2026
## Summary Prepare stable CLI 3.0.2 by merging current `main` into `release/v3` and setting explicit stable release metadata. ## CLI package commits since 3.0.1 - `1f11cdaf1` perf(cli): add in-memory caching for redundant TDP reads (#2902) - `2a969dd29` Fix CLI template issues and remove AI/MCP/MCPClient templates (#2904) - `553685c6b` Confirm interactive RSC permission updates (#2906) - `082e79830` Merge main into release/v3 for CLI 3.0.2 - `17d2170a6` Prepare CLI 3.0.2 release ## Validation - `npx turbo build --filter=@microsoft/teams.cli` - `npm -w @microsoft/teams.cli test` --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Corina <14900841+corinagum@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Umang <3513186+umangsehgal@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: SirajShaik-MSFT <v-sirshaikh@microsoft.com> Co-authored-by: Hugo Gonzalez <hugogonzalez@microsoft.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Kavin <115390646+singhk97@users.noreply.github.com> Co-authored-by: Rido <rido-min@users.noreply.github.com> Co-authored-by: Ricky Castaneda <126518272+MSFTRickyCastaneda@users.noreply.github.com> Co-authored-by: Shanmathi Mayuram Krithivasan <37715033+ShanmathiMayuramKrithivasan@users.noreply.github.com> Co-authored-by: Nick Walker <nickwalk@microsoft.com> Co-authored-by: Mehak Bindra <mhk0397@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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
Adds process-scoped in-memory caching to eliminate redundant TDP (Teams Developer Portal) network reads within a single
teamsCLI invocation. Started with app-detail reads (the worst hotspot) and extended to bot reads, with a small reusable caching layer shared by both.Caches are process-scoped (one CLI invocation = one process),
Map-backed, and clone-on-read/write (structuredClone) so callers can't corrupt cached objects. Writes refresh the cache from authoritative POST responses; mutations that bypass the normal path explicitly invalidate.What changed
src/utils/resource-cache.ts: genericcreateResourceCache<T>()with clone-safeget/set/invalidate.hotspot #1) —fetchAppDetailsV2is now cache-first with a{ force }opt-out;updateAppDetailswrite-refreshes from its POST response (souploadIconbenefits);importAppPackageinvalidates. This collapses the ~7–9GET /appdefinitions/v2/{id}reads perteams app update(read-modify-write) down to 1.hotspot #2) —fetchBotandgetBotLocationnow share a singleGET /botframework/{botId}round-trip via onereadBotResource()classifier (200 → Teams-managed with details, 404 → Azure). Only those two meaningful outcomes are cached; other statuses throw uncached so transient failures still retry.updateBotrefreshes;deleteBot/registerBotinvalidate.fetchAppDetailkeeps its spinner silent when both underlying reads are already warm (fixes the duplicate spinner seen on App → details → back → details).Tests
app-details-cache.test.ts,bot-cache.test.ts.RUN_INTEGRATION=1) demonstrating the saved round-trips.tsc --noEmitandnpm run buildclean.Notes
update.ts,doctor.ts,bot/migrate.ts,bot-handler.ts) was traced for read-after-write staleness; all refresh or invalidate correctly.