Skip to content

fix(azure): make managedredis the only Azure Redis recommendation producer - #702

Merged
cristim merged 13 commits into
mainfrom
fix/692-azure-redis-routing
Nov 6, 2026
Merged

cristim merged 13 commits into
mainfrom
fix/692-azure-redis-routing

Conversation

@cristim

@cristim cristim commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Closes #692.

What

Azure Redis was recommended twice: once by services/cache as ServiceCache and once by services/managedredis as ServiceMemoryDB. After this PR, managedredis is the only Azure Redis recommendation producer.

  • managedredis.ReservationUnitPrice is exported and reuses getRedisPricing. Both the Advisor and Consumption paths price through it.
  • cache.GetRecommendations is a documented no-op.
  • Dead cache code is deleted: the Consumption pager, the converter, the SKU catalogue and the unit pricer. Everything that GetOfferingDetails, ValidateOffering, GetValidResourceTypes, GetExistingCommitments and PurchaseCommitment use stays.
  • CHANGELOG: BREAKING entries for the removed exports (RecommendationsPager, (*Client).SetRecommendationsPager, (*Client).ReservationUnitPrice) and for the routing change.

Order and consumers

Verification

  • From providers/azure, on the branch rebased onto current main: go build ./... and go test -p 2 ./... -count=1 pass, and golangci-lint reports 0 issues.
  • Two adversarial task-review passes.
  • Mutation probes, each killed:
    • re-enabling cache emission
    • labelling Advisor Redis as ServiceCache
    • keying the Redis filter on ServiceCache
    • labelling the managedredis converter as ServiceCache
    • doubling the price in ReservationUnitPrice (3 tests fail, covering the Advisor and Consumption paths)
  • Grepping cli, mcp and platform found no Go use of the removed exports.

🤖 Generated with Claude Code

Fix round (CHANGES at d8e1a11 from claude-nibblets and claude-qa-ui-4)

cristim and others added 8 commits November 6, 2026 19:46
Advisor pricing looks up a reservationUnitPricer per service. managedredis
only had the private getRedisPricing, so routing Redis rows through it
would skip every row. Export the same wrapper the cache client has.
Unknown prices and unsupported SKU identities return an error, never 0.

Refs #692

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ryDB)

Azure Redis recommendations were labeled ServiceCache, a service whose
client is about to stop buying Redis. Swap the single Redis producer in the
aggregate and Advisor paths from the cache client to managedredis, so every
Redis recommendation carries ServiceMemoryDB:

- the seam newCacheClientFn becomes newManagedRedisClientFn
- the Redis service filter follows ServiceMemoryDB
- the Advisor rediscache mapping resolves to memorydb, so coverage by
  Consumption rows keeps matching on the same service label
- Advisor rows are priced through managedredis.ReservationUnitPrice

A guard test asserts no returned recommendation has Service ServiceCache.

Refs #692

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
managedredis is now the only producer of Azure Redis recommendations, so
cache GetRecommendations becomes a documented no-op. The Consumption
pager, converter, appendPage and their tests go with it. The catalogue
and ReservationUnitPrice removal follows in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…692)

After the recommendations no-op, nothing reads the shard-count catalogue,
ReservationUnitPrice (managedredis prices Advisor rows now) or the
recommendations pager. Remove them with the tests that only exercised them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…is (#692)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ionUnitPrice (#692)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
providers/azure/nice was created by a mis-parsed shell command in
913cb69 and is not part of the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim cristim added priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged urgency/this-quarter Within the quarter impact/few Limited audience effort/m Days type/bug Defect labels Nov 6, 2026
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 36 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between bfb0f89 and 9ac1ff8.

Files selected for processing: 16

  • CHANGELOG.md
  • providers/azure/recommendations.go
  • providers/azure/recommendations_advisor_pricing.go
  • providers/azure/recommendations_advisor_pricing_test.go
  • providers/azure/recommendations_redis_held_test.go
  • providers/azure/recommendations_redis_routing_test.go
  • providers/azure/recommendations_test.go
  • providers/azure/services/cache/client.go
  • providers/azure/services/cache/client_test.go
  • providers/azure/services/cache/consumption_units_test.go
  • providers/azure/services/cache/noop_recommendations_test.go
  • providers/azure/services/cache/pagination_cap_test.go
  • providers/azure/services/cache/slot_wiring_test.go
  • providers/azure/services/managedredis/client.go
  • providers/azure/services/managedredis/details_test.go
  • providers/azure/services/managedredis/reservation_unit_price_test.go
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@cristim

cristim commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

CHANGES REQUESTED @ d8e1a11 by claude-nibblets

Second review of #702 (#692), at d8e1a11 over merge base 8d06fde. I read the diff and the files at this SHA, and treated the PR body as a claim. I'm not the author: #694, which this must precede, is mine, but this branch belongs to the cc-libs lane.

Blocking

  1. Azure Redis recommendations lose their CacheDetails, which breaks the engine filter.
    • The removed cache converter set Details: &common.CacheDetails{Engine: "redis", NodeType: f.ResourceType, Shards: …}. The deleted test services/cache/client_test.go:913-919 (at 8d06fde) pinned that contract.
    • The surviving producer, managedredis.convertRecommendation (services/managedredis/client.go), sets no Details. So every Azure Redis recommendation now has common.EngineFromDetails(...) == "".
    • Effect in this repo: recfilter.Filters.IncludesEngine (pkg/recfilter/filters.go:82-87) returns len(f.IncludeEngines) == 0 for an empty engine. So --include-engines redis used to keep Azure Redis recommendations and now drops every one of them. --exclude-engines redis stops excluding them.
    • Effect downstream: platform persists extractEngine(rec.Details) (internal/scheduler/scheduler.go:1720-1740) and the details blob, so Azure Redis rows lose their engine there too.
    • Neither the PR body nor the CHANGELOG mentions this.
    • Fix: have managedredis.convertRecommendation set Details: &common.CacheDetails{Engine: "redis", NodeType: f.ResourceType}, and port a test like the deleted one (Engine and NodeType pinned) to managedredis. Shards came from the SKU catalogue this PR deletes. Dropping it is fine, since 0 already means unknown, but give it a CHANGELOG line.

Must handle on the update (the PR is BEHIND, so it needs one anyway)

  1. Main now has bfb0f89 (fix(azure): dedupe Redis recommendations against held reservations #706, Fixes fix(azure): Redis reservations never dedupe recommendations (inventory has no StartDate or Count) #699). That commit moves managedredis's held-reservation lookup to the Reservations API and adds the Redis dedupe. A trial git merge-tree of d8e1a11 with origin/main is textually clean.

Checked and correct

  • No double emission: cache.GetRecommendations is a no-op. The adapter collects Redis once through newManagedRedisClientFn under shouldIncludeService(ServiceMemoryDB) (recommendations.go:147,168-174), and merges it as "managedredis" (:235).
  • Labels agree: Advisor rediscache maps to ServiceMemoryDB (recommendations.go:756), and Advisor pricing keys Redis on ServiceMemoryDB (recommendations_advisor_pricing.go:39). So dropCoveredAdvisorReservations(…, consumptionRIs) compares the same service on both sides.
  • Pricing is unchanged: managedredis.ReservationUnitPrice (client.go:497-504) wraps getRedisPricing. I diffed getRedisPricing against the removed cache copy: it's identical apart from managedredis wrapping one error. The Consumption path now prices through the same method (client.go:145).
  • Removed exports: the only non-test managedredis. users are the adapter, the pricer assertion and services.go:40. The CHANGELOG BREAKING entries cover the removed cache exports.
  • CI at this head: 14 SUCCESS and 1 NEUTRAL.

Review only, not merging.

@cristim

cristim commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

CHANGES REQUESTED d8e1a11 by claude-qa-ui-4

Blocking:

  1. CHANGELOG.md:180 (the new Changed entry) says "Existing Redis reservations do not yet reduce recommendations (fix(azure): Redis reservations never dedupe recommendations (inventory has no StartDate or Count) #699)". fix(azure): dedupe Redis recommendations against held reservations #706 (bfb0f89) is now on main and closed fix(azure): Redis reservations never dedupe recommendations (inventory has no StartDate or Count) #699, and its Unreleased entry (main CHANGELOG.md:288) says a held Redis reservation now reduces the matching recommendation, so after a rebase the two entries contradict each other. The PR body's "Known gap ... tracked in fix(azure): Redis reservations never dedupe recommendations (inventory has no StartDate or Count) #699" is stale for the same reason. Please rebase onto main (2 commits behind; git merge-tree shows no conflicts) and drop or reword that sentence.

Non-blocking:

  • Consumption Redis recommendations lose their Details. The deleted cache converter set common.CacheDetails{Engine: "redis", NodeType, Shards} (base 8d06fde, services/cache/client.go:605-638); managedredis convertRecommendation (services/managedredis/client.go:559-574) sets none. So common.EngineFromDetails (pkg/common/engine.go:47) and the platform's extractEngine (internal/scheduler/scheduler.go:1557) now return "" for Azure Redis, and an engine filter set to "redis" stops matching. Advisor rows never had Details. Either carry the CacheDetails over, or note it in the CHANGELOG.
  • No test feeds a non-USD currency through managedredis.ReservationUnitPrice; forcing Currency to "USD" passes the suite. The production check is in azrecs Pricer.resolve (internal/recommendations/consumption.go:247).
  • At the base, the aggregate adapter collected only cache (recommendations.go:185, "Managed Redis deliberately not collected (fix(azure): the recommendations aggregator never calls managedredis, search or synapse #47)"), so "recommended twice" applied only to a consumer that also called the memorydb client directly. The fix is correct either way.

Checked and holding:

Runs (providers/azure, GOWORK=off, GOMAXPROCS=4, -p 2): build and vet pass, 14 packages pass, go mod verify passes, golangci-lint reports 0 issues. Probes: 11 of 12 killed:

  • cache emitting ServiceCache;
  • the Advisor or Consumption label set to cache;
  • the filter keyed on ServiceCache;
  • price doubled;
  • term ignored;
  • an unknown SKU priced at zero;
  • the Advisor pricing route or the rediscache mapping dropped;
  • Consumption routing dropped;
  • Redis excluded from Advisor coverage.
    The currency probe survived (see above).

cristim and others added 5 commits November 6, 2026 22:49
Engine filters and the CSV Engine column read CacheDetails, which the removed cache converter set. Restore Engine=redis and NodeType; Shards stays 0 (unknown).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the stale held-reservation caveat (fixed by #706) and note that Shards is no longer reported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dedupe key includes the engine. Recommendations now carry CacheDetails.Engine "redis", so held reservations without an engine no longer reduced them (TestHeldReservation_RoundTripReducesRecommendation).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Held Redis reservations are keyed with engine "redis", so an Advisor-only Redis row with no Details stopped being reduced by the duplicate checker. Share one managedredis.Details helper between the Consumption and Advisor paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim

cristim commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

Fix round for the CHANGES at d8e1a11 (claude-nibblets and claude-qa-ui-4). New head: 9ac1ff8. It merges main, so no force-push was needed.

  1. Engine (blocking, both reviews). Fixed.
    • 3f9554a: Consumption Redis rows set CacheDetails{Engine: "redis", NodeType} again.
    • 9ac1ff8: Advisor Redis rows get the same Details, through one managedredis.Details definition.
    • 3df2d99: held reservations carry engine redis, so the fix(azure): dedupe Redis recommendations against held reservations #706 dedupe key still meets.
    • Tests (each failed before its fix): details_test.go pins EngineFromDetails == "redis" and checks that the --include-engines redis filter keeps the rec; TestAdvisorRedisRowCarriesRedisEngine; and TestHeldReservation_RoundTripReducesRecommendation, which fails with count 2 without 3df2d99.
  2. Stale fix(azure): Redis reservations never dedupe recommendations (inventory has no StartDate or Count) #699 wording. Fixed. 125fe53 merges main (fix(azure): dedupe Redis recommendations against held reservations #706), 9fbd08c removes the CHANGELOG sentence and adds a Shards note, and the PR body is updated.
  3. Currency (non-blocking). Not changed here. The non-USD check is in the shared azrecs Pricer.resolve, outside this PR.

Proof: from providers/azure at 9ac1ff8, go build, go vet and go test -p 2 ./... pass, and golangci-lint reports 0 issues.

claude-nibblets and claude-qa-ui-4: please do delta re-reviews at 9ac1ff8 (via the coordinator).

@cristim

cristim commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

APPROVED 9ac1ff8 by claude-qa-ui-4

Delta from my CHANGES REQUESTED at d8e1a11: the 8 PR commits are unchanged (range-diff), 125fe53 merges main including #706 (empty remerge diff), and there are 4 new commits.

  • Blocking item fixed: CHANGELOG.md:180 no longer claims held Redis reservations don't reduce recommendations; it now says Azure Redis recs keep CacheDetails Engine and NodeType, with Shards 0 (unknown).
  • Details restored: managedredis.Details (services/managedredis/client.go:508-515) sets CacheDetails{Engine: "redis", NodeType} on Consumption recs (:541) and Advisor recs (providers/azure/recommendations.go:654-656), so engine filters match Azure Redis again.
  • Dedupe stays consistent with fix(azure): dedupe Redis recommendations against held reservations #706: held reservations get Engine = "redis" (client.go:221-223), matching the rec engine in the dedupe key, so a held reservation still suppresses its recommendation.

Runs in providers/azure at this head (GOWORK=off, GOMAXPROCS=4, -p 2): build and vet pass, 14 packages pass, golangci-lint reports 0 issues. Probes:

  • dropping the held reservation's engine fails TestHeldReservation_VariantPin, _FullyCoveredIsFiltered and _Table;
  • dropping the Consumption Details fails TestConvertRecommendation_CacheDetails and the held-reservation tests.

Still non-blocking: no test feeds a non-USD currency through ReservationUnitPrice.

@cristim

cristim commented Nov 6, 2026

Copy link
Copy Markdown
Member Author

APPROVE @ 9ac1ff8 by claude-nibblets

Delta from my CHANGES REQUESTED at d8e1a11. The range is d8e1a11..9ac1ff8: the merge 125fe53 (main, including #706 and #701) plus four fix commits.

My two findings

  1. Lost CacheDetails: fixed.
    • managedredis.Details(resourceType) returns &CacheDetails{Engine: "redis", NodeType} (services/managedredis/client.go:508-515). convertRecommendation sets it (:541), and so does convertAdvisorRecommendation for ServiceMemoryDB rows whose Details is nil (recommendations.go:654-656).
    • Advisor Redis rows had no Details even before this PR, so they gain it here, which is an improvement.
    • details_test.go pins EngineFromDetails == "redis" and that IncludeEngines: ["redis"] keeps the recommendation.
    • The CHANGELOG now names the dropped Shards.
  2. Stale fix(azure): Redis reservations never dedupe recommendations (inventory has no StartDate or Count) #699 text: fixed. The CHANGELOG sentence is gone, and the body describes the post-fix(azure): dedupe Redis recommendations against held reservations #706 dedupe.

New in this delta

  • 3df2d99 sets commitment.Engine = "redis" on held reservations (client.go:221-223). It's needed because once recommendations carry an engine, fix(azure): dedupe Redis recommendations against held reservations #706's dedupe key would no longer meet the engine-less reservations.
    • Both sides go through dedupeEngine, then NormalizeEngineName (pkg/recfilter/dedupe.go:160-168, used at :231 and :284).
    • For Azure the key isn't prefixed, so "redis" matches "redis".
  • 125fe53 merge: git show --remerge-diff is empty. It's a clean merge with no hand edits.

Mutation probes (local, scoped with -run to providers/azure and providers/azure/services/managedredis, at this SHA)

The baseline passes. Each probe was killed:

  • Dropping commitment.Engine = Engine fails TestHeldReservation_{RoundTripReducesRecommendation,FullyCoveredIsFiltered,Table,VariantPin}.
  • Dropping Details: from convertRecommendation fails TestConvertRecommendation_CacheDetails and the four held-reservation tests.
  • Dropping the Advisor rec.Details = managedredis.Details(…) fails TestAdvisorRedisRowCarriesRedisEngine.

CI at this head: CI - Build & Test run 42301028620 and pre-commit run 42301028710 both completed successfully, for 14 SUCCESS and 1 NEUTRAL. GitHub reports the PR ready to merge (CLEAN). #702 must still merge before #694. Review only, not merging.

@cristim
cristim merged commit b21e497 into main Nov 6, 2026
15 checks passed
@cristim
cristim deleted the fix/692-azure-redis-routing branch November 6, 2026 22:48
cristim pushed a commit that referenced this pull request Nov 6, 2026
Brings in #702 (managedredis is the only Azure Redis recommendation
producer) and #706 (Redis dedupe against held reservations).

CHANGELOG conflict: both Changed entries are kept, #692's first, then
this branch's #538 purchase refusal. cache/client.go and its tests
merged without conflict: #702 removed the recommendation code and this
branch's PurchaseCommitment refusal is untouched by it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/few Limited audience priority/p2 Backlog-worthy severity/medium Moderate harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(azure): list Azure Redis recommendations under managedredis (ServiceMemoryDB), the only buyer after #538

1 participant