class GraphQL::Dataloader::AsyncDataloader
Public Class Methods
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 12 def self.install_graphql_methods if !Async::Task.method_defined?(:cancel) Async::Task.alias_method(:cancel, :stop) end if !Async::Task.method_defined?(:graphql_async_dataloader_run) Async::Task.attr_accessor(:graphql_async_dataloader_run) Async::Task.attr_accessor(:graphql_async_dataloader_condition) end end
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 22 def initialize(...) super create_pending_run end
Calls superclass method
GraphQL::Dataloader::new
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 7 def self.use(...) install_graphql_methods super end
Calls superclass method
GraphQL::Dataloader::use
Public Instance Methods
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 195 def active_run @pending_run || current_task_run || raise(GraphQL::Error, "No available Run to append to, GraphQL-Ruby bug") end
# File lib/graphql/dataloader/async_dataloader.rb, line 186 def append_job(callable = nil, &block) active_run.jobs.push(callable || block) nil end
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 29 def create_pending_run jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit @pending_run = Run.new(self, total_fiber_limit, jobs_fiber_limit) end
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 202 def current_task_run run = Async::Task.current?&.graphql_async_dataloader_run run if run&.dataloader.equal?(self) end
The current taskβs run, but only if it belongs to this dataloader. A different dataloader may be running inside one of our tasks (or vice versa), e.g. a query executed from a resolver or a subscription trigger; its run must not be reused.
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 191 def lazy_at_depth(depth, lazy) active_run.lazies_at_depth[depth] << lazy end
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 243 def run(trace_query_lazy: nil) trace = Fiber[:__graphql_current_multiplex]&.current_trace run = @pending_run || current_task_run || raise(GraphQL::Error, "No available Run, GraphQL-Ruby internal bug") @pending_run = nil run.trace = trace first_pass = true #: bool trace&.begin_dataloader(self) fiber_vars = get_fiber_variables raised_error = nil #: StandardError? jobs = run.jobs Sync do |_maybe_new_task| # Make sure there's a new task instance to hold `.graphql_...` state: task = Async::Task.new do |root_task| run.root_task = root_task root_task.graphql_async_dataloader_run = run # Tasks inherit the spawning fiber's storage; give this run its own execution state. Fiber[:__graphql_runtime_info] = nil set_fiber_variables(fiber_vars) while first_pass || run.running? || !jobs.empty? first_pass = false run_queue(run, run.snoozed_jobs_condition, :jobs) run_queue(run, run.snoozed_sources_condition, :sources) if !run.lazies_at_depth.empty? with_trace_query_lazy(trace_query_lazy) do if enqueue_next_pending_lazies(run.lazies_at_depth) run_queue(run, run.snoozed_jobs_condition, :jobs) end end end end rescue StandardError => err raised_error = err root_task.cancel end task.run task.wait end create_pending_run if raised_error raise raised_error end trace&.end_dataloader(self) rescue UncaughtThrowError => e throw e.tag, e.value end
Source
# File lib/graphql/dataloader/async_dataloader.rb, line 207 def run_isolated previous_run = current_task_run prev_pending_keys = {} #: Hash[GraphQL::Dataloader::Source, Hash[untyped, untyped]] # Clear pending loads but keep already-cached records # in case they are useful to the given block. @source_cache.each do |source_class, batched_sources| batched_sources.each do |batch_args, batched_source_instance| if batched_source_instance.pending? prev_pending_keys[batched_source_instance] = batched_source_instance.pending.dup batched_source_instance.pending.clear end end end res = nil #: untyped create_pending_run @pending_run.jobs << -> { res = yield } run res ensure if previous_run Async::Task.current.graphql_async_dataloader_run = previous_run # clear the one created in #run: @pending_run = nil end prev_pending_keys = prev_pending_keys #: as !nil prev_pending_keys.each do |source_instance, pending| pending.each do |key, value| next if source_instance.results.key?(key) queue_pending_source(source_instance) if source_instance.pending.empty? source_instance.pending[key] = value end end end
# File lib/graphql/dataloader/async_dataloader.rb, line 34 def yield(source = Fiber[:__graphql_current_dataloader_source]) task = Async::Task.current run = task.graphql_async_dataloader_run trace = run.trace trace&.dataloader_fiber_yield(source) if !run.push_task_message(:paused_task, task) task.stop end condition = task.graphql_async_dataloader_condition condition.wait if !run.push_task_message(:resumed_task, task) task.stop end trace&.dataloader_fiber_resume(source) nil end