Skip to content

fix(azure/gcp/aws): add ctx.Err() guards and page-cap to all pagination loops #691

Description

@cristim

Summary

Pagination loops across the Azure and GCP provider clients are missing ctx.Err() checks between pages and have no maximum-page budget. This is the same failure shape fixed in PR #690 for the 7 AWS services -- discovered during the survey requested in #688.

All affected loops are unbounded and lack an early-exit on context cancellation. When running under a Lambda deadline these loops can eat the entire remaining budget before the SDK surfaces the cancellation error.

Affected locations

Azure -- for pager.More() { pager.NextPage(ctx) } without ctx.Err() check (smell #2)

  • providers/azure/services/compute/client.go:136 -- GetRecommendations
  • providers/azure/services/compute/client.go:171 -- GetExistingCommitments
  • providers/azure/services/compute/client.go:362 -- GetValidResourceTypes
  • providers/azure/services/cache/client.go:136 -- GetRecommendations
  • providers/azure/services/cache/client.go:170 -- GetExistingCommitments
  • providers/azure/services/cache/client.go:359 -- GetValidResourceTypes
  • providers/azure/services/database/client.go:138 -- GetRecommendations
  • providers/azure/services/database/client.go:172 -- GetExistingCommitments
  • providers/azure/services/cosmosdb/client.go:139 -- GetRecommendations
  • providers/azure/services/cosmosdb/client.go:173 -- GetExistingCommitments
  • providers/azure/services/cosmosdb/client.go:364 -- GetValidResourceTypes
  • providers/azure/services/search/client.go:136 -- GetRecommendations
  • providers/azure/services/search/client.go:170 -- GetExistingCommitments
  • providers/azure/services/search/client.go:358 -- GetValidResourceTypes

GCP -- iterator loops without ctx.Err() check (smell #2)

  • providers/gcp/services/computeengine/client.go:205 -- GetRecommendations iterator
  • providers/gcp/services/computeengine/client.go:247 -- GetExistingCommitments iterator
  • providers/gcp/services/computeengine/client.go:441 -- GetValidResourceTypes iterator
  • providers/gcp/services/cloudsql/client.go:163 -- GetRecommendations iterator
  • providers/gcp/services/memorystore/client.go:163 -- GetRecommendations iterator
  • providers/gcp/services/memorystore/client.go:203 -- GetExistingCommitments iterator

Minimum fix (small effort)

For each for pager.More() loop body, add at the top:

if err := ctx.Err(); err != nil {
    return nil, fmt.Errorf("context cancelled during pagination: %w", err)
}

For each GCP for { it.Next() } loop body, same guard.

Add a const maxPages = 50 (or suitable value) page budget per loop with a warning log when hit, matching the pattern from PR #690.

Context

A separate issue covers the Azure Retail Prices API NextPageLink truncation (smell #5) in the same files -- that fix is larger and touches the HTTP-level pricing helpers.

Activity

  1. cristim commented on May 22, 2026

    @cristim
    MemberAuthor

    Scope extension: AWS rec-collection (same ctx-cancellation smell)

    Folding in 2 AWS findings from the AWS-only follow-up survey (#688 punch-list). Same smell #2 (ctx.Err() not treated as terminal), same fix shape -- belongs in this issue alongside the Azure/GCP loops.

    AWS -- ctx-cancellation accumulated as skippable failure instead of returning immediately

    • providers/aws/recommendations/client.go:119-120 -- GetAllRecommendations loops over services calling GetRecommendationsForService(ctx, service). On error (including context.Canceled / context.DeadlineExceeded) it logs and continues, returning partial results with nil error at line 126. Callers cannot distinguish a complete sweep from one that timed out halfway.
    • providers/aws/recommendations/client.go:452-454 -- getSavingsPlansRecommendations has the same pattern across SP types (line 463 returns partial results with nil error after a per-type error swallow).

    Fix shape (same as the Azure/GCP fix)

    Inside each per-service / per-type loop body, before continuing:

    if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
        return nil, fmt.Errorf("%s recommendations cancelled: %w", service, err)
    }

    Project memory entry: feedback_ctx_cancel_terminal.md -- ctx cancellation is terminal in fan-out loops, never accumulated as lastErr and continued.

    Other AWS findings (separate issue needed)

    Three other AWS findings from the survey are different smells and warrant their own issue, not this one:

    • recommendations/client.go:79 -- GetReservationPurchaseRecommendation single-page (smell Remove Hard SES dependency #5, correctness bug, silently misses RIs beyond page 1 on large payer accounts)
    • recommendations/client.go:446 -- GetSavingsPlansPurchaseRecommendation single-page (same shape for SP)
    • cmd/multi_service.go:1335 -- DescribeDBMajorEngineVersions single-page

    A fourth finding (ctx-cancellation in a DescribeDBInstances fan-out) is low-risk side-path and can ride with the single-page ones.

  2. changed the title [-]fix(azure/gcp): add ctx.Err() guards and page-cap to all pagination loops[/-] [+]fix(azure/gcp/aws): add ctx.Err() guards and page-cap to all pagination loops[/+] on May 22, 2026
  3. cristim commented on May 28, 2026

    @cristim
    MemberAuthor

    Verification: cannot-verify-autopilot - Partially shipped. PR #693 (merged 2026-05-22) adds pagination to three AWS API calls (CE recommendations, RDS engine versions). However, the issue explicitly asks for ctx.Err() guards and page-cap in Azure and GCP pagination loops. No commit in the git history for feat/multicloud-web-frontend addresses Azure or GCP pagination loops with ctx.Err() guards.

  4. added a commit that references this issue on May 31, 2026
    f4d7cdd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions