AsyncDataloader will run GraphQL::Dataloader::Source#fetch calls in parallel, so that external service calls (like database queries or network calls) don’t have to wait in a queue.
To use AsyncDataloader, hook it up in your schema instead of GraphQL::Dataloader:
- use GraphQL::Dataloader + use GraphQL::Dataloader::AsyncDataloader Also, add the async gem to your project, for example:
bundle add async Now, GraphQL::Dataloader::AsyncDataloader will create Async::Task instances instead of plain Fibers and the async gem will manage parallelism.
For a demonstration of this behavior, see: https://github.com/rmosolgo/rails-graphql-async-demo
You can also implement manual parallelism using dataloader.yield.
For Rails, you’ll need Rails 7.1, which properly supports fiber-based concurrency, and you’ll also want to configure Rails to use Fibers for isolation:
class Application < Rails::Application # ... config.active_support.isolation_level = :fiber end You can use Dataloader’s Fiber lifecycle hooks to improve ActiveRecord connection handling:
release_connection calls to improve this.isolation_level = :fiber, new Fibers don’t inherit connected_to ... settings from their parent fibers.Altogether, it can be improved like this:
def get_fiber_variables vars = super # Collect the current connection config to pass on: vars[:connected_to] = { role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, prevent_writes: ActiveRecord::Base.current_preventing_writes } vars end def set_fiber_variables(vars) connection_config = vars.delete(:connected_to) # Reset connection config from the parent fiber: ActiveRecord::Base.connecting_to(**connection_config) super(vars) end def cleanup_fiber super # Release the current connection ActiveRecord::Base.connection_pool.release_connection end Modify the example according to your database configuration and abstract class hierarchy.
You can also manually implement parallelism with Dataloader. See the Dataloader Parallelism guide for details.