Repository navigation
refactor(aws): move the capped Cost Explorer loops onto the shared pagination helper - #463
Conversation
Independent review verdict: CLEAN at 8e33717Reviewer: fresh Claude agent (Sonnet, high effort), not the author, cold brief. The PR body was treated as a claim. Coordinator: claude-cc-reviewer. Scope: Blocking findings: none. All five loops errored at the cap before and still do, and none truncates. The purchase-recommendation loop is unchanged in behaviour.
Token threading: every site sets the input token from the callback argument, and the helper ends the loop on a nil or empty token. The helper takes the next token from the callback's return value, so a site cannot forget to thread it. Note (non-blocking):
What was attacked and how (providers/aws,
Gate: merge after #462. Then retarget this PR to |
51855eb to
8906050
Compare
8e33717 to
0ab32e0
Compare
|
CI is green on head |
0ab32e0 to
b81b120
Compare
b81b120 to
d33dc8f
Compare
…gination helper
Migrate the five already-capped loops (RI recommendations, SP coverage,
SP covered series, on-demand series, SP commitment rate) onto paginateCE.
Caps are unchanged (20 each) and each site keeps its accumulation and fetch
error wrapping. sp_commitment_rate gains the per-page ctx check and keeps
its ErrNoSPCommitmentRate page index through a closure counter.
Wording changes:
- A canceled ctx is returned raw; sp coverage ("pagination canceled"),
sp covered series ("pagination canceled"), GetOnDemandSeries ("context
canceled during pagination") and sp commitment rate (wrapped on fetch)
no longer wrap it.
- The cap text is unified to "<what>: pagination cap reached after N pages".
GetOnDemandSeries used "exceeded N page cap; possible CE token loop";
the RI and SP coverage texts lose their issue #692 suffixes.
No existing test asserted the old wording.
Closes #35
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d33dc8f to
1e1a41e
Compare
fetchGroupedDayCoverage was the only Cost Explorer token loop in the package left uncapped after LeanerCloud#462/LeanerCloud#463. Route it through paginateCE with maxCoveragePages so endless fresh tokens or a token cycle stop at the cap with an error; keep the repeated-token check as a fast failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(aws): batch daily coverage sparkline fetch per region AttachDailyUsageHistory issued one GetReservationCoverage request per distinct (service, region, instance type), so CE requests scaled with SKU count. Group recommendations by (service, region). Buckets with more distinct types than lookback days now issue one region-wide request per day grouped by INSTANCE_TYPE (CE rejects DAILY granularity combined with GroupBy, so a single grouped request cannot return a daily series) and fan each type's series out to its recommendations. Smaller buckets keep the existing per-type DAILY request, so a bucket never costs more than min(types, lookback days) requests plus continuation pages. Per-type series, missing-day zeros and nil-for-no-data semantics match the per-type path; a failed grouped fetch leaves the bucket's usage history nil instead of reporting zero coverage. Closes #85 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(aws): stop grouped coverage paging on a repeated page token If Cost Explorer returned the same NextPageToken twice, the grouped per-day loop re-requested the same page until ctx was canceled. Return an error instead (CodeRabbit finding on #464). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(aws): cap grouped daily coverage paging through paginateCE fetchGroupedDayCoverage was the only Cost Explorer token loop in the package left uncapped after #462/#463. Route it through paginateCE with maxCoveragePages so endless fresh tokens or a token cycle stop at the cap with an error; keep the repeated-token check as a fast failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Cristian Magherusan-Stanciu <cristim@users.noreply.github.com>
Summary
This is PR 2 of 2 for #35. It is stacked on #462 (PR 1), so merge #462 first and then retarget this PR to
main. CI only runs on PRs tomain.It moves the five Cost Explorer loops that already had a cap onto the shared
paginateCEhelper from #462:client.gomaxRecommendationPagessp_coverage.gomaxSPCoveragePagessp_coverage_series.gomaxSPCoveragePagesondemand_series.gomaxOnDemandSeriesPagessp_commitment_rate.goEvery cap stays at 20. Each callback keeps its existing accumulation and its fetch-error wraps, including
sp commitment rate: %w,GetOnDemandSeries: %w,sp coverage: %wandsp covered series: %w. The "recommendation absent on page %d" index insp_commitment_ratecomes from a closure counter and keeps the same 0-based numbering.Wording changes, listed in the commit body:
errors.Isstill matches.<what>: pagination cap reached after N pages, for example "RI EC2: pagination cap reached after 20 pages".sp_commitment_ratenow checks ctx before each page. Before, it made one call even when ctx was already canceled.collection_sp.gois still excluded on purpose, because it merges partial pages.ratelimiter.go(#432) andparser_ri.go(#452) are untouched.Closes #35 (with #462).
Verification (macOS, Go 1.26.9)
(cd providers/aws && GOWORK=off go test -race -short ./...)passes, and no existing test changed.make buildandmake vetpass. golangci-lint v2.10.1 (the CI pin) reports 0 issues. gofmt is clean.TestGetSPCoveredSeries_CapsEndlessTokens,TestGetOnDemandSeries_CapsEndlessTokens,TestGetSPCommitmentRate_CapsEndlessTokens. Each asserts the literal cap of 20 and the call count, using the bounded mock.TestGetSPCommitmentRate_PreCanceledContext.AbsentRecommendationReportsPageIndex("page 1"),SPCommitmentRate_FetchErrorKeepsPrefixandGetOnDemandSeries_FetchErrorKeepsPrefix.+= 28e33717.Fakes only; no AWS call.
🤖 Generated with Claude Code
Summary by CodeRabbit