Repository navigation
fix(aws/recs): cap coverage/utilization CE calls with shared semaphore - #1218
Conversation
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 8 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis PR adds semaphore-based concurrency gating to AWS Cost Explorer API calls in ChangesSemaphore integration for Cost Explorer calls
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
3bb6521 to
7705441
Compare
7705441 to
22a530e
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
Adversarial reviewReviewed against Verified (no change needed)
Findings (non-blocking, file follow-ups)
Failing CI (unrelated, pre-existing on
|
|
@coderabbitai full review |
✅ Action performedFull review finished. |
22a530e to
ce2e7f2
Compare
|
@coderabbitai review |
✅ Action performedReview finished.
|
fetchCoveragePage and fetchUtilizationPage called the Cost Explorer SDK
without acquiring the shared concurrency semaphore, so the scheduler's
coverage-enrichment fan-out (AttachDailyUsageHistory per service, region,
resourceType tuple) escaped the CUDLY_MAX_PARALLELISM cap that protects
Lambda memory and CE rate limits. Worst case added roughly 6 x min(N,20)
uncapped concurrent CE calls on top of the capped 20, and made the
GetAllRecommendations docstring invariant ("the Acquire/Release boundary
lives around the individual CE SDK call") false for a third of the CE
call sites.
Wrap both SDK calls in concurrency.Acquire/Release, holding the slot
only across the outbound call (released during rate-limit backoffs),
matching fetchRIPageWithRetry and fetchSPPageWithRetry. Add regression
tests that saturate a capacity-1 shared semaphore and assert the CE mock
is never reached (both fail on the pre-fix code), plus a slot-release
guard against Acquire/Release pairing leaks.
Closes #1144
ce2e7f2 to
e3861ea
Compare
|
Rebased onto origin/main (73166c2). Clean rebase. Gates: go build, go vet, gocyclo -over 10, golangci-lint (0 new issues). Tests: providers/aws/recommendations (1 pass, all ok). |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Merged to main (rebased onto current main, CLEAN + all CI green; closes #1144). hold the concurrency slot only around the outbound CE call, not the whole coverage/utilization sweep (semaphore-at-API-call). |
Problem
Closes #1144 (review finding PERF-02, P2)
fetchCoveragePageandfetchUtilizationPageinproviders/aws/recommendations/called the Cost Explorer SDK without acquiring the shared concurrency semaphore. The scheduler's coverage-enrichment phase (AttachDailyUsageHistory, looping per (service, region, resourceType) tuple from each of the 6 concurrent service goroutines) therefore escaped theCUDLY_MAX_PARALLELISMcap that was installed specifically to protect Lambda memory and Cost Explorer rate limits - worst case roughly 6 x min(N, 20) uncapped concurrent CE calls on top of the capped 20. It also made theGetAllRecommendationsdocstring invariant ("the Acquire/Release boundary lives around the individual CE SDK call") false for a third of the CE call sites.Fix
Wrap both SDK calls in
concurrency.Acquire/concurrency.Release, holding the slot only across the outbound call (so slots are free during rate-limit backoff waits), exactly matching the existingfetchRIPageWithRetryandfetchSPPageWithRetrypattern. All four CE call sites in the package now honor the cap, so theGetAllRecommendationsdocstring needed no change. Docstrings on both fetchers document the boundary.Tests
New
concurrency_cap_test.go:TestFetchCoveragePage_RespectsSharedSemaphoreandTestFetchUtilizationPage_RespectsSharedSemaphorereplicate the real scenario: a saturated capacity-1 shared semaphore on the context (the scheduler's collection path under load) plus cancellation, asserting the CE mock is never reached andcontext.Canceledis surfaced. Both FAIL on the pre-fix code (verified viagit stash: "An error is expected but got nil", mock called) and pass post-fix.TestFetchPages_ReleaseSemaphoreSlotguards the Acquire/Release pairing: after successful fetches the slot must be available again (no leak).Verification run:
go test ./recommendations/(fromproviders/aws/): 334 passedgo vet ./recommendations/: cleango build ./...in both the root module andproviders/aws: successNote:
go test -raceflags a pre-existing data race on the sharedrateLimiter(Resetfrom concurrent service sweeps, e.g.TestGetAllRecommendations_IncludesSavingsPlans); it reproduces identically onorigin/mainwithout this change and is out of scope here.Summary by CodeRabbit
Tests
Refactor