Skip to content

Conversation

@zsmoore
Copy link

@zsmoore zsmoore commented Jan 6, 2026

See discussion in - #256
Build on #243

Allow for custom dispatch strategies

Right now the dispatch strategy (in this PR and the original busy strategy) do not need dataloader references, they just need registry references. Its possible that strategies prefer to have the DL loaded such as a DFS strategy to trigger the dl dispatch immediately without using a registry reference but as there is no current need do not include it.

Because of the circular reference dependency between dispatch strategy and registry, choose to add a bootstrap function into the interface to give a reference to the strategy

BFS strategy handles dispatching in a level by level fashion see example here -

i.e.

Async Path

A
    B (async)
        E
        F
    C
        G (async)
        H
    D
        I
        J

A dispatches immediately, queues B, C, D
B, C, D dispatch queue G, H, I, J
Thread is spawned to wait for B to finish and retry every 30 ms
B finishes, queues E, F
E, F, G, H, I, J dispatched

This dispatch strategy also handles chained dataloaders but beyond that handles ASYNC chained dataloaders such that a dataloader makes an api call then chains a subsequent dataloader.

This is done with minimal thread overload by doing dispatchAll + only queueing a single thread when work is known to exist but not be completed

Added some tests to verify some behavior of the dispatch strategy

@zsmoore
Copy link
Author

zsmoore commented Jan 6, 2026

Note to self to follow up on - I believe thinking on this again this may be a greedy level by level traversal rather than true BFS. I will come back to this and add a more complicated test to replicate the example I have to verify if async are waited on a level basis or we continue dispatching to child levels when work is known and only wait if we are blocked on just async calls

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a dispatch strategy framework for DataLoaders, allowing custom control over when and how DataLoader batches are dispatched. The primary implementation is a breadth-first search (BFS) dispatch strategy that handles synchronous and asynchronous chained DataLoaders by dispatching level-by-level with a fallback mechanism for async operations.

  • Adds a new DispatchStrategy interface with lifecycle hooks (onRegistryCreation, loadCalled, loadCompleted)
  • Implements BreadthFirstChainedDispatchStrategy with automatic BFS dispatching and scheduled fallback for async scenarios
  • Integrates dispatch strategies into DataLoaderRegistry and DataLoaderOptions for configuration

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
src/main/java/org/dataloader/DispatchStrategy.java New public API interface defining dispatch strategy lifecycle methods with a NO_OP default implementation
src/main/java/org/dataloader/strategy/BreadthFirstChainedDispatchStrategy.java New BFS strategy implementation with fallback dispatch mechanism for async chained loaders
src/main/java/org/dataloader/DataLoaderRegistry.java Integrates dispatch strategy into registry builder, applies strategy to all registered DataLoaders
src/main/java/org/dataloader/DataLoaderOptions.java Adds dispatch strategy field and builder methods to options
src/main/java/org/dataloader/DataLoaderHelper.java Calls dispatch strategy lifecycle hooks when loads are initiated and completed
src/main/java/org/dataloader/registries/ScheduledDataLoaderRegistry.java Updates to use NO_OP dispatch strategy (maintains existing behavior)
src/test/java/org/dataloader/strategy/BreadthFirstChainedDispatchStrategyTest.java Comprehensive test suite covering single-depth, chained, async, and level-by-level dispatch scenarios
src/test/java/org/dataloader/DataLoaderCacheMapTest.java Updates expected dependent counts to account for dispatch strategy hooks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@graphql-java graphql-java deleted a comment from Copilot AI Jan 6, 2026
zsmoore and others added 15 commits January 8, 2026 13:07
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…tchStrategy.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…tchStrategy.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@zsmoore
Copy link
Author

zsmoore commented Jan 8, 2026

Note to self to follow up on - I believe thinking on this again this may be a greedy level by level traversal rather than true BFS. I will come back to this and add a more complicated test to replicate the example I have to verify if async are waited on a level basis or we continue dispatching to child levels when work is known and only wait if we are blocked on just async calls

Wrote out a fairly complicated test in GreedyLevelByLevelChainedDispatchStrategyStressTest to verify the behavior in practice. As a result renamed this as its not a true BFS. In practice we see increased batch sizes compared to our previous ticker mode with scheduled registry so while this is not a true level by level traversal we still see a great balance of speed + efficiency in our real life scenario

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