Skip to content

feat: schedule fetch trees optimally - #1612

Merged
ysmolski merged 24 commits into
feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraphfrom
yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping
Aug 13, 2026
Merged

feat: schedule fetch trees optimally#1612
ysmolski merged 24 commits into
feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraphfrom
yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping

Conversation

@ysmolski

@ysmolski ysmolski commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

scheduleFetches is a dependency-aware scheduler that emits nested Sequence/Parallel trees, collapsing independent chains onto their own branches instead of synchronizing them at wave barriers.

This scheduler tries to break the top level DAG into weakly connected components. For each component it picks between two strategies of scheduling:

  • the waves tree, that barriers all ready roots per step,
  • the inlined tree, that pulls each root's exclusively-reachable descendants into that root's branch.

This scheduler implements a strategy that is guaranteed to be strictly the best condering all possible makespans of fetches.

According to production data, recursive wave scheduling provides the most value. It creates wave tree that is deep and where fetches already ordered in the order of dependencies. Inlining gives about 3-5% improvements on top of that.

Summary by CodeRabbit

  • New Features

    • Added optional dependency-aware scheduling for fetch execution.
    • Added configuration support for enabling scheduled fetch processing.
    • Scheduling supports parallel execution while preserving dependency order and subscription behavior.
    • Retains existing processing behavior through fallback when scheduling is unavailable.
  • Bug Fixes

    • Improved duplicate dependency handling and deterministic fetch ordering.
    • Added validation for invalid, cyclic, or unsupported schedules.
  • Tests

    • Expanded coverage for dependency graphs, cycles, large plans, subscriptions, multi-fetch scenarios, and scheduler fallback.

@ysmolski
ysmolski requested a review from a team as a code owner July 23, 2026 14:13

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0e9d9238-8ff2-4777-9d2d-2f7a23380952

📥 Commits

Reviewing files that changed from the base of the PR and between 5ad74b9 and ca0fbbc.

⛔ Files ignored due to path filters (3)
  • execution/go.sum is excluded by !**/*.sum
  • go.work.sum is excluded by !**/*.sum
  • v2/go.sum is excluded by !**/*.sum
📒 Files selected for processing (10)
  • execution/engine/engine_config.go
  • execution/engine/execution_engine.go
  • execution/engine/execution_engine_schedule_fetches_test.go
  • execution/go.mod
  • v2/go.mod
  • v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_connect_test.go
  • v2/pkg/engine/datasourcetesting/datasourcetesting.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/resolve_input_templates_test.go
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
💤 Files with no reviewable changes (2)
  • v2/pkg/engine/datasourcetesting/datasourcetesting.go
  • v2/pkg/engine/postprocess/resolve_input_templates_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • execution/engine/execution_engine.go
  • execution/engine/engine_config.go
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
  • v2/pkg/engine/postprocess/postprocess.go

📝 Walkthrough

Walkthrough

The change adds optional dependency-aware fetch scheduling with validation and legacy fallback. It adds execution configuration, expands scheduler tests and benchmarks, simplifies fetch-tree test construction, renames the post-processor test helper, updates module dependencies, and revises gRPC test-server setup.

Changes

Fetch scheduling feature

Layer / File(s) Summary
Fetch-tree test DSL
v2/pkg/engine/postprocess/util_test.go, v2/pkg/engine/postprocess/*_test.go
Adds helpers for constructing, materializing, comparing, and rendering fetch trees. Existing postprocess tests use the helpers.
Dependency ordering normalization and coverage
v2/pkg/engine/postprocess/order_sequence_by_dependencies.go, v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go
Compacts sorted dependency IDs in place. Tests use structural comparisons and cover dependency ordering and tie-breaking.
Fetch DAG scheduling algorithm
v2/pkg/engine/postprocess/schedule_fetches.go
Builds dependency graphs, creates wave or inlined schedules, handles components and cycles, validates schedules, and normalizes output trees.
Optional scheduler processor wiring
v2/pkg/engine/postprocess/postprocess.go, execution/engine/*, v2/pkg/engine/datasourcetesting/datasourcetesting.go, v2/pkg/engine/datasource/graphql_datasource/*_test.go
Adds scheduler configuration and processor integration. Renames WithDefaultCustomPostProcessor to WithPostProcessor and updates test setup.
Scheduler validation and integration coverage
v2/pkg/engine/postprocess/schedule_fetches_test.go, execution/engine/execution_engine_schedule_fetches_test.go
Adds scenario, invariant, fallback, subscription, randomized property, integration, and benchmark coverage.
Supporting build and test-server updates
v2/go.mod, execution/go.mod, v2/pkg/engine/datasource/grpc_datasource/grpc_datasource_connect_test.go
Updates Go module versions and configures the gRPC test server for HTTP/1 and unencrypted HTTP/2 directly.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ExecutionEngine
  participant FetchTreeProcessors
  participant scheduleFetches
  participant LegacyOrganizers
  ExecutionEngine->>FetchTreeProcessors: Enable scheduled fetch processing
  FetchTreeProcessors->>scheduleFetches: ProcessFetchTree(root)
  scheduleFetches-->>FetchTreeProcessors: Return scheduled tree or error
  FetchTreeProcessors->>LegacyOrganizers: Organize tree when disabled, ineligible, or failed
  LegacyOrganizers-->>FetchTreeProcessors: Return legacy-organized tree
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding optimal scheduling for fetch trees.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping

Comment @coderabbitai help to get the list of available commands.

@ysmolski
ysmolski force-pushed the yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping branch 3 times, most recently from 711710c to be19712 Compare July 23, 2026 14:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
v2/pkg/engine/postprocess/order_sequence_by_dependencies.go (1)

55-66: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard nodeDependsOn against cyclic dependencies. buildSchedule already errors on self-dependencies and cycles, and scheduleFetches falls back to orderSequenceByDependencies on that path. In the fallback, nodeDependsOn recurses without a visited/in-progress set, so cyclic input can still blow the stack. Add cycle detection here and re-enable the disabled cycle/self-dependency tests in v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go#L193-L207.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/engine/postprocess/order_sequence_by_dependencies.go` around lines 55
- 66, Guard orderSequenceByDependencies.nodeDependsOn against recursive cycles
by tracking visited or in-progress fetch IDs and stopping recursion when a
dependency is already being traversed, while preserving deduplicated sorted
results. In v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go
lines 193-207, re-enable the disabled self-dependency and cycle tests to verify
the fallback no longer overflows the stack.
🧹 Nitpick comments (2)
v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go (1)

193-207: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Disabled cycle/self-dependency tests reflect the unguarded-recursion gap.

See the consolidated comment for details — these stubs are disabled because nodeDependsOn in order_sequence_by_dependencies.go has no cycle protection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go` around
lines 193 - 207, Re-enable and satisfy the cycle and self-dependency tests for
orderSequenceByDependencies. Update nodeDependsOn to track visited nodes during
recursive dependency traversal, terminating safely when a node is revisited
while preserving correct dependency ordering for acyclic graphs.
v2/pkg/engine/postprocess/schedule_fetches.go (1)

429-464: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer cmp.Compare over subtraction in the sort comparator.

minReachableFetchID(a) - minReachableFetchID(b) is the classic subtraction-comparator overflow footgun for slices.SortFunc. Practically safe today since FetchIDs stay small, but cmp.Compare removes the risk for free.

♻️ Proposed fix
+	"cmp"
 	"fmt"
 	"math"
 	"slices"
...
 		slices.SortFunc(out, func(a, b *resolve.FetchTreeNode) int {
-			return minReachableFetchID(a) - minReachableFetchID(b)
+			return cmp.Compare(minReachableFetchID(a), minReachableFetchID(b))
 		})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/engine/postprocess/schedule_fetches.go` around lines 429 - 464, Update
the comparator in combineOf’s parallel sorting branch to use cmp.Compare on the
two minReachableFetchID results instead of subtracting them, and add the
required cmp import if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@v2/pkg/engine/postprocess/order_sequence_by_dependencies.go`:
- Around line 55-66: Guard orderSequenceByDependencies.nodeDependsOn against
recursive cycles by tracking visited or in-progress fetch IDs and stopping
recursion when a dependency is already being traversed, while preserving
deduplicated sorted results. In
v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go lines 193-207,
re-enable the disabled self-dependency and cycle tests to verify the fallback no
longer overflows the stack.

---

Nitpick comments:
In `@v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go`:
- Around line 193-207: Re-enable and satisfy the cycle and self-dependency tests
for orderSequenceByDependencies. Update nodeDependsOn to track visited nodes
during recursive dependency traversal, terminating safely when a node is
revisited while preserving correct dependency ordering for acyclic graphs.

In `@v2/pkg/engine/postprocess/schedule_fetches.go`:
- Around line 429-464: Update the comparator in combineOf’s parallel sorting
branch to use cmp.Compare on the two minReachableFetchID results instead of
subtracting them, and add the required cmp import if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d4d83f89-bd6b-4ad4-97ed-1104340551cc

📥 Commits

Reviewing files that changed from the base of the PR and between 826c838 and 711710c.

📒 Files selected for processing (8)
  • v2/pkg/engine/postprocess/add_missing_nested_dependencies_test.go
  • v2/pkg/engine/postprocess/create_parallel_nodes_test.go
  • v2/pkg/engine/postprocess/order_sequence_by_dependencies.go
  • v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/schedule_fetches.go
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
  • v2/pkg/engine/postprocess/util_test.go

@ysmolski
ysmolski requested a review from devsergiy July 23, 2026 15:02

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
v2/pkg/engine/datasourcetesting/datasourcetesting.go (1)

60-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the legacy scheduling bypass explicit in the helper API.

WithPostProcessor now always appends DisableScheduleFetches(), so its generic name hides that callers cannot use it to exercise the default scheduler. Keep a clearly named legacy helper and provide a scheduled variant, or document this invariant prominently, to prevent future integration tests from silently bypassing scheduler coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/engine/datasourcetesting/datasourcetesting.go` around lines 60 - 70,
Make the scheduling behavior explicit around WithPostProcessor: retain a clearly
named legacy helper that appends DisableScheduleFetches(), and add a distinct
scheduled variant that does not append it, or prominently document the invariant
if the API cannot be split. Ensure callers can intentionally exercise the
default scheduler instead of silently bypassing it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@v2/pkg/engine/datasourcetesting/datasourcetesting.go`:
- Around line 60-70: Make the scheduling behavior explicit around
WithPostProcessor: retain a clearly named legacy helper that appends
DisableScheduleFetches(), and add a distinct scheduled variant that does not
append it, or prominently document the invariant if the API cannot be split.
Ensure callers can intentionally exercise the default scheduler instead of
silently bypassing it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 01c2af0d-a656-4760-9a51-43ad200c3bcc

📥 Commits

Reviewing files that changed from the base of the PR and between 8549124 and 015663e.

📒 Files selected for processing (9)
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_defer_test.go
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_federation_entity_interfaces_test.go
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_federation_test.go
  • v2/pkg/engine/datasourcetesting/datasourcetesting.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/postprocess_test.go
  • v2/pkg/engine/postprocess/resolve_input_templates_test.go
  • v2/pkg/engine/postprocess/schedule_fetches.go
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
  • v2/pkg/engine/postprocess/schedule_fetches.go

@ysmolski ysmolski changed the title feat: schedule deeply nested fetch-trees optimally feat: schedule fetch trees optimally Jul 24, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

Comment thread v2/pkg/engine/postprocess/util_test.go Outdated
Comment thread v2/pkg/engine/postprocess/util_test.go Outdated
Comment thread v2/pkg/engine/postprocess/util_test.go Outdated
Comment thread v2/pkg/engine/postprocess/util_test.go Outdated
Comment thread v2/pkg/engine/postprocess/util_test.go Outdated
Comment thread v2/pkg/engine/postprocess/util_test.go
Comment thread v2/pkg/engine/postprocess/postprocess.go
Comment thread v2/pkg/engine/postprocess/schedule_fetches_test.go Outdated
Comment thread v2/pkg/engine/postprocess/schedule_fetches_test.go Outdated
Comment thread v2/pkg/engine/postprocess/schedule_fetches.go Outdated
Comment thread v2/pkg/engine/postprocess/schedule_fetches_test.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@v2/pkg/engine/postprocess/schedule_fetches_test.go`:
- Line 1035: Update the test to invoke the fallback processor directly through
NewProcessor().fetchTreeProcessors.organizeFetchTree(scheduled) instead of
(*scheduleFetches).ProcessFetchTree. Preserve the existing invalid scheduled
input and assertions while verifying the legacy processor fallback contract
rather than discarding ProcessFetchTree’s error.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 665deb82-8f8b-40ee-b17a-888658781cf2

📥 Commits

Reviewing files that changed from the base of the PR and between 3967e63 and e9e33ed.

📒 Files selected for processing (7)
  • v2/pkg/engine/postprocess/add_missing_nested_dependencies_test.go
  • v2/pkg/engine/postprocess/create_parallel_nodes_test.go
  • v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/schedule_fetches.go
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
  • v2/pkg/engine/postprocess/util_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • v2/pkg/engine/postprocess/create_parallel_nodes_test.go
  • v2/pkg/engine/postprocess/add_missing_nested_dependencies_test.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/order_sequence_by_dependencies_test.go

Comment thread v2/pkg/engine/postprocess/schedule_fetches_test.go
@ysmolski
ysmolski requested a review from devsergiy August 11, 2026 11:09
Comment thread v2/pkg/engine/postprocess/schedule_fetches_test.go Outdated
@ysmolski
ysmolski changed the base branch from master to feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph August 12, 2026 09:47
@ysmolski
ysmolski force-pushed the yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping branch from 5dc42a7 to 5ad74b9 Compare August 12, 2026 10:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
execution/engine/execution_engine.go (1)

161-163: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add an engine-level regression test for this configuration bridge.

The scheduler option-wiring test exercises postprocess.NewProcessor directly. It does not verify that Configuration.EnableScheduleFetches() causes NewExecutionEngine to add postprocess.EnableScheduleFetches(). Add a test that enables the configuration flag and verifies the scheduled fetch tree or the resulting postProcessorOptions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@execution/engine/execution_engine.go` around lines 161 - 163, The existing
configuration bridge in NewExecutionEngine lacks engine-level coverage. Add a
regression test that enables Configuration.EnableScheduleFetches(), constructs
NewExecutionEngine, and verifies that postprocess.EnableScheduleFetches() is
present through the scheduled-fetch tree or resulting postProcessorOptions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@execution/engine/execution_engine.go`:
- Around line 161-163: The existing configuration bridge in NewExecutionEngine
lacks engine-level coverage. Add a regression test that enables
Configuration.EnableScheduleFetches(), constructs NewExecutionEngine, and
verifies that postprocess.EnableScheduleFetches() is present through the
scheduled-fetch tree or resulting postProcessorOptions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e6a3c79f-bab1-4596-96da-9f8e92b300ae

📥 Commits

Reviewing files that changed from the base of the PR and between 5ad74b9 and 307924a.

📒 Files selected for processing (6)
  • execution/engine/engine_config.go
  • execution/engine/execution_engine.go
  • v2/pkg/engine/datasourcetesting/datasourcetesting.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/resolve_input_templates_test.go
  • v2/pkg/engine/postprocess/schedule_fetches_test.go
💤 Files with no reviewable changes (2)
  • v2/pkg/engine/postprocess/resolve_input_templates_test.go
  • v2/pkg/engine/datasourcetesting/datasourcetesting.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • v2/pkg/engine/postprocess/schedule_fetches_test.go

@ysmolski
ysmolski force-pushed the yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping branch from ca0fbbc to ed0729d Compare August 13, 2026 08:35
scheduleFetches is a dependency-aware scheduler that emits nested
Sequence/Parallel trees, collapsing independent chains onto their own
branches instead of synchronizing them at wave barriers.

This scheduler tries to break the top level DAG into weakly connected
components. For each component it picks between two strategies of
scheduling:
  - the waves tree, that barriers all ready roots per step,
  - the inlined tree, that pulls each root's exclusively-reachable
    descendants into that root's branch.

This scheduler implements a strategy that is guarnteed to be not the
worst combination condering all possible makespans of fetches.
# Conflicts:
#	v2/pkg/engine/postprocess/postprocess.go
When both the scheduler and multi-fetch are enabled, organizeFetchTree runs
the legacy wave pipeline as a scratch phase to discover maximal same-wave
merge groups, merges them via createMultiFetch, flattens the wave tree back
into the flat Sequence the scheduler consumes, and schedules the merged DAG.
A MultiEntityFetch participates as one node (min member ID, union
dependencies; dependents are rewired by mergeGroup), so this needs no
scheduler changes.

Rationale: scheduling before merging dissolves the same-wave antichains that
batching needs (eBay celestial query: 71 requests vs 43), while merging first
keeps maximal batching AND the scheduler's dominance proof then holds against
the merged wave tree — the result is provably never slower than the legacy
waves + multi-fetch pipeline, usually structurally better (independent chains
leave the wave barriers). An adaptive in-scheduler variant (branch
experiment/mf-in-scheduler) buys one more request on the eBay query at
beta=0.005 but costs a cost model, policy portfolio and greedy search; not
worth the complexity.

Known follow-ups, unchanged from the multi-fetch review: the sjson v1.0.4
workspace pin (multi-fetch is a no-op in consumer builds without it), and
computing waves internally instead of materializing the throwaway legacy tree.
@ysmolski
ysmolski force-pushed the yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping branch from ed0729d to 9af0428 Compare August 13, 2026 09:06
@ysmolski
ysmolski merged commit bd03deb into master Aug 13, 2026
19 checks passed
@ysmolski
ysmolski deleted the yury/router-579-reduce-federated-query-latency-by-improving-fetch-grouping branch August 13, 2026 10:11
ysmolski pushed a commit that referenced this pull request Aug 13, 2026
🤖 I have created a release *beep* *boop*
---


##
[2.16.0](v2.15.1...v2.16.0)
(2026-08-13)


### Features

* implement multi fetch to the same subgraph
([#1594](#1594))
([22584e2](22584e2))
* schedule fetch trees optimally
([#1612](#1612))
([bd03deb](bd03deb))


### Bug Fixes

* check interface implementation in `potentiallySameObject` for
nullability relaxation
([#1454](#1454))
([5bacb9e](5bacb9e))
* improve handling of nullable lists for required fields
([#1631](#1631))
([0af4dd3](0af4dd3))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: wundergraph-bot[bot] <285992168+wundergraph-bot[bot]@users.noreply.github.com>
ysmolski added a commit to wundergraph/cosmo that referenced this pull request Aug 13, 2026
This PR adds two feature flags for the Cosmo's Query Planner:
                                     
`engine.enable_multi_fetch`

This option merges entity fetches that target the same subgraph and 
execute at the same point in the query plan 
into a single request with aliased `_entities` fields. 
This reduces the number of requests sent to subgraphs. 
env: ENGINE_ENABLE_MULTI_FETCH

`engine.enable_schedule_fetches`

This feature replaces the wave-based fetch execution 
with a dependency-aware fetch scheduler. 
Independent fetch chains progress as soon as 
their own dependencies complete,
instead of waiting for the slowest fetch in each wave.                                                                                                                    
env: ENGINE_ENABLE_SCHEDULE_FETCHES

By default, these features are disabled:
```
engine:
  enable_multi_fetch: false       
  enable_schedule_fetches: false 
```

Built on top of wundergraph/graphql-go-tools#1612
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