Skip to content

Fix N+1 ES queries causing timeout in LinksController#index - #4304

Closed
gumclaw wants to merge 2 commits into
mainfrom
fix/links-api-n-plus-one-es-queries
Closed

Fix N+1 ES queries causing timeout in LinksController#index#4304
gumclaw wants to merge 2 commits into
mainfrom
fix/links-api-n-plus-one-es-queries

Conversation

@gumclaw

@gumclaw gumclaw commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

What

Batch Elasticsearch queries for sales_count and sales_usd_cents in Api::V2::LinksController#index to eliminate N+1 query pattern.

  • Add batch_successful_sales_counts and batch_total_usd_cents class methods to Product::Stats using ES terms aggregation on product_id
  • Preload batched stats in LinksController#index when scopes include view_sales or account
  • Use preloaded values in as_json_for_api with fallback to individual queries for backward compatibility

Why

The index action was calling successful_sales_count and total_usd_cents individually on each product (2 ES queries per product). For users with many products, this caused Rack::Timeout::RequestTimeoutException after 120s. This change reduces 2N ES queries to just 2 total queries using per-product terms aggregation.

Test Results

Added tests for:

  • batch_successful_sales_counts returns correct per-product counts
  • batch_total_usd_cents returns correct per-product net revenue
  • as_json_for_api uses preloaded data when provided
  • LinksController#index calls batch methods instead of per-product queries

AI disclosure: Built with Claude Opus 4.6. Prompted to fix the N+1 ES query pattern in Api::V2::LinksController#index that was causing Rack::Timeout::RequestTimeoutException.

The index action was calling successful_sales_count and total_usd_cents
individually on each product when scopes include view_sales/account,
resulting in 2N Elasticsearch queries. For users with many products,
this caused Rack::Timeout (120s) exceptions.

Add batch_successful_sales_counts and batch_total_usd_cents class
methods to Product::Stats that use ES terms aggregation on product_id
to fetch per-product values in just 2 queries total. The controller
preloads these and passes them through as_json_options, with fallback
to individual queries for other callers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gumclaw

gumclaw commented Apr 6, 2026

Copy link
Copy Markdown
Contributor Author

Closing as duplicate: shares identical changes to product/stats.rb and product/as_json.rb with #4305.

@gumclaw gumclaw closed this Apr 6, 2026
@gianfrancopiana
gianfrancopiana deleted the fix/links-api-n-plus-one-es-queries branch April 25, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants