graphql 2.6.3 → 2.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16abc9c2a5eda0da251dbe7e14433241bc7d038d2527926832ceb29336fb857a
4
- data.tar.gz: c89bd2a4b340ca30bfa7b823f51e4671972355d54bd56fdaed598c13a415c3b3
3
+ metadata.gz: 9f149d55f546745aa90807691e6ad3bc31528f341e6055ffc2146a06df033175
4
+ data.tar.gz: 4c153cc3bdd4ec208dbcf4e98de46834e8abd19bd338d553034245a452b84546
5
5
  SHA512:
6
- metadata.gz: 6452d2a517c502b4a8934582d060885a5f6462de244a1f331433f1076dc57a879cdd081e147f70925064a99607e0794fcf6eadad7a3f4a9111a5ab979c552554
7
- data.tar.gz: b6a0219606d905fc885ab2192596d1acb1d92bce407defc751bfafb1a7199e9c32275c1d3202f3246251e72b80554698b1f54920f76178f1ddc81b41d628bacd
6
+ metadata.gz: 6f663ca7de9f4943173238e3bde41d06d9cd36cf1fbdeabffd8096e19bdd00fd62ec1a6d4aa4f3938297e94d090d0b1f1013931def778c77f7519ae598bcd431
7
+ data.tar.gz: 2d76f7eff773781453598832e119c16f589ac8f8644cba892fa137fbaf4aa29545eed4f1606f731192dce4af1ff065101cf00a436eb257da4864a687e4b644ac
@@ -29,14 +29,14 @@ module GraphQL
29
29
  future_complexity
30
30
  end
31
31
  when nil
32
- subject.logger.warn <<~GRAPHQL
32
+ subject.logger.warn <<~MESSAGE
33
33
  GraphQL-Ruby's complexity cost system is getting some "breaking fixes" in a future version. See the migration notes at https://graphql-ruby.org/api-doc/#{GraphQL::VERSION}/GraphQL/Schema.html#complexity_cost_calculation_mode_for-class_method
34
34
 
35
35
  To opt into the future behavior, configure your schema (#{subject.schema.name ? subject.schema.name : subject.schema.ancestors}) with:
36
36
 
37
37
  complexity_cost_calculation_mode(:future) # or `:legacy`, `:compare`
38
38
 
39
- GRAPHQL
39
+ MESSAGE
40
40
  max_possible_complexity(mode: :legacy)
41
41
  else
42
42
  raise ArgumentError, "Expected `:future`, `:legacy`, `:compare`, or `nil` from `#{query.schema}.complexity_cost_calculation_mode_for` but got: #{query.schema.complexity_cost_calculation_mode.inspect}"
@@ -1,86 +1,234 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module GraphQL
3
4
  class Dataloader
4
5
  class AsyncDataloader < Dataloader
5
6
  def yield(source = Fiber[:__graphql_current_dataloader_source])
6
- trace = Fiber[:__graphql_current_multiplex]&.current_trace
7
+ run = Fiber[:__graphql_async_dataloader_run]
8
+ trace = run.trace
7
9
  trace&.dataloader_fiber_yield(source)
8
- if (condition = Fiber[:graphql_dataloader_next_tick])
9
- condition.wait
10
- else
11
- Fiber.yield
12
- end
10
+ task = Async::Task.current
11
+ run.finished_tasks.push(task)
12
+ condition = Fiber[:__graphql_async_dataloader_condition]
13
+ condition.wait
14
+ run.started_tasks.push(task)
13
15
  trace&.dataloader_fiber_resume(source)
14
16
  nil
15
17
  end
16
18
 
17
- def run(trace_query_lazy: nil)
18
- trace = Fiber[:__graphql_current_multiplex]&.current_trace
19
- jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
20
- job_fibers = []
21
- next_job_fibers = []
22
- source_tasks = []
23
- next_source_tasks = []
24
- first_pass = true
25
- sources_condition = Async::Condition.new
26
- manager = spawn_fiber do
27
- trace&.begin_dataloader(self)
28
- while first_pass || !job_fibers.empty?
29
- first_pass = false
30
- fiber_vars = get_fiber_variables
19
+ class Run
20
+ def initialize(root_task, trace, total_fiber_limit, jobs_fiber_limit)
21
+ @root_task = root_task
22
+ @trace = trace
23
+ @total_fiber_limit = total_fiber_limit
24
+ @jobs_fiber_limit = jobs_fiber_limit
31
25
 
32
- run_pending_steps(job_fibers, next_job_fibers, source_tasks, jobs_fiber_limit, trace)
26
+ @finished_tasks = nil
27
+ @started_tasks = nil
28
+ @started_count_task = nil
29
+ @finished_count_task = nil
30
+ @finished_all_tasks = nil
31
+ @finished_first_pass = nil
33
32
 
34
- Sync do |root_task|
35
- set_fiber_variables(fiber_vars)
36
- while !source_tasks.empty? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) }
37
- while (task = (source_tasks.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size + next_source_tasks.size) < total_fiber_limit) && spawn_source_task(root_task, sources_condition, trace))))
38
- if task.alive?
39
- root_task.yield # give the source task a chance to run
40
- next_source_tasks << task
41
- end
33
+ @snoozed_jobs_condition = Async::Condition.new
34
+ @snoozed_sources_condition = Async::Condition.new
35
+ end
36
+
37
+ attr_reader :root_task, :trace, :jobs_fiber_limit, :total_fiber_limit, :finished_tasks, :started_tasks, :snoozed_jobs_condition, :snoozed_sources_condition
38
+
39
+
40
+ def jobs_bandwidth?
41
+ running_count < jobs_fiber_limit
42
+ end
43
+
44
+ def allowed_sources_tasks
45
+ within_limit = total_fiber_limit - running_count
46
+ if within_limit < 1
47
+ 1
48
+ else
49
+ within_limit
50
+ end
51
+ end
52
+
53
+ def close_queues
54
+ @finished_tasks.close
55
+ @finished_count_task.cancel
56
+
57
+ @started_tasks.close
58
+ @started_count_task.cancel
59
+ end
60
+
61
+ def running_count
62
+ @snoozed_jobs_condition.instance_variable_get(:@ready).num_waiting +
63
+ @snoozed_sources_condition.instance_variable_get(:@ready).num_waiting +
64
+ @started_count +
65
+ @started_tasks.size -
66
+ @finished_count
67
+ end
68
+
69
+ def wait_for_queues
70
+ if !@finished_first_pass.resolved?
71
+ @finished_first_pass.resolve(true)
72
+ end
73
+
74
+ @finished_all_tasks.wait
75
+ @finished_all_tasks = Async::Promise.new
76
+ end
77
+
78
+ def new_queues
79
+ @finished_tasks = Async::Queue.new
80
+ @finished_count = 0
81
+ @started_tasks = Async::Queue.new
82
+ @started_count = 0
83
+ @finished_first_pass = Async::Promise.new
84
+ @finished_all_tasks = Async::Promise.new
85
+
86
+ @started_count_task = @root_task.async do
87
+ @finished_first_pass.wait
88
+ while _t = @started_tasks.wait
89
+ @started_count += 1
90
+ if @finished_count == @started_count
91
+ @finished_all_tasks.resolve(true)
92
+ end
93
+ end
94
+ end
95
+
96
+ @finished_count_task = @root_task.async do
97
+ while t_or_err = @finished_tasks.wait
98
+ if t_or_err.is_a?(StandardError)
99
+ @finished_all_tasks.reject(t_or_err)
100
+ else
101
+ @finished_count +=1
102
+ if @finished_count == @started_count
103
+ @finished_all_tasks.resolve(true)
42
104
  end
43
- sources_condition.signal
44
- source_tasks.concat(next_source_tasks)
45
- next_source_tasks.clear
46
105
  end
47
106
  end
107
+ end
108
+ end
109
+
110
+ def running?
111
+ @snoozed_jobs_condition.waiting? || @snoozed_sources_condition.waiting?
112
+ end
113
+ end
114
+
115
+ def run(trace_query_lazy: nil)
116
+ trace = Fiber[:__graphql_current_multiplex]&.current_trace
117
+ jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
118
+ first_pass = true
119
+ trace&.begin_dataloader(self)
120
+ fiber_vars = get_fiber_variables
121
+ raised_error = nil
122
+ Sync do |root_task|
123
+ run = Run.new(root_task, trace, total_fiber_limit, jobs_fiber_limit)
124
+ set_fiber_variables(fiber_vars)
125
+
126
+ while first_pass || run.running? || !@pending_jobs.empty?
127
+ first_pass = false
128
+ run_pending_steps(run)
129
+ run_sources(run)
48
130
 
49
131
  if !@lazies_at_depth.empty?
50
132
  with_trace_query_lazy(trace_query_lazy) do
51
- run_next_pending_lazies(job_fibers, trace)
52
- run_pending_steps(job_fibers, next_job_fibers, source_tasks, jobs_fiber_limit, trace)
133
+ run_next_pending_lazies(run)
134
+ run_pending_steps(run)
53
135
  end
54
136
  end
55
137
  end
56
- trace&.end_dataloader(self)
138
+ rescue StandardError => err
139
+ raised_error = err
140
+ root_task.cancel
57
141
  end
58
142
 
59
- manager.resume
60
- if manager.alive?
61
- raise "Invariant: Manager didn't terminate successfully: #{manager}"
143
+ if raised_error
144
+ raise raised_error
62
145
  end
63
-
146
+ trace&.end_dataloader(self)
64
147
  rescue UncaughtThrowError => e
65
148
  throw e.tag, e.value
66
149
  end
67
150
 
68
151
  private
69
152
 
70
- def run_pending_steps(job_fibers, next_job_fibers, source_tasks, jobs_fiber_limit, trace)
71
- while (f = (job_fibers.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size) < jobs_fiber_limit) && spawn_job_fiber(trace))))
72
- if f.alive?
73
- finished = run_fiber(f)
74
- if !finished
75
- next_job_fibers << f
153
+ def run_pending_steps(run)
154
+ run.new_queues
155
+
156
+ if (unsnoozed = run.snoozed_jobs_condition.waiting?)
157
+ run.snoozed_jobs_condition.signal
158
+ end
159
+
160
+ while (!@pending_jobs.empty? && (has_limit = run.jobs_bandwidth?)) || (unsnoozed)
161
+ unsnoozed = false
162
+ if has_limit
163
+ spawn_job_task(run)
164
+ end
165
+ run.wait_for_queues
166
+ end
167
+ ensure
168
+ run.close_queues
169
+ end
170
+
171
+ def spawn_job_task(run)
172
+ if !@pending_jobs.empty?
173
+ fiber_vars = get_fiber_variables
174
+ run.root_task.async do |task|
175
+ run.trace&.dataloader_spawn_execution_fiber(@pending_jobs)
176
+ Fiber[:__graphql_async_dataloader_run] = run
177
+ Fiber[:__graphql_async_dataloader_condition] = run.snoozed_jobs_condition
178
+ set_fiber_variables(fiber_vars)
179
+ run.started_tasks.push(task)
180
+ while job = @pending_jobs.shift
181
+ job.call
76
182
  end
183
+ ensure
184
+ cleanup_fiber
185
+ run.finished_tasks.push($! || task)
186
+ run.trace&.dataloader_fiber_exit
77
187
  end
78
188
  end
79
- job_fibers.concat(next_job_fibers)
80
- next_job_fibers.clear
81
189
  end
82
190
 
83
- def spawn_source_task(parent_task, condition, trace)
191
+ def run_sources(run)
192
+ run.new_queues
193
+
194
+ if (unsnoozed = run.snoozed_sources_condition.waiting?)
195
+ run.snoozed_sources_condition.signal
196
+ end
197
+
198
+ allowed_tasks = run.allowed_sources_tasks
199
+ while (has_pending = @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) } ) || unsnoozed
200
+ unsnoozed = false
201
+ if has_pending
202
+ spawn_source_task(run, allowed_tasks)
203
+ end
204
+ run.wait_for_queues
205
+ end
206
+ ensure
207
+ run.close_queues
208
+ end
209
+
210
+ #### TODO DRY Had to duplicate to remove spawn_job_fiber
211
+ def run_next_pending_lazies(run)
212
+ smallest_depth = nil
213
+ @lazies_at_depth.each_key do |depth_key|
214
+ smallest_depth ||= depth_key
215
+ if depth_key < smallest_depth
216
+ smallest_depth = depth_key
217
+ end
218
+ end
219
+
220
+ if smallest_depth
221
+ lazies = @lazies_at_depth.delete(smallest_depth)
222
+ if !lazies.empty?
223
+ lazies.each_with_index do |l, idx|
224
+ append_job { l.value }
225
+ end
226
+ spawn_job_task(run) # Todo what was the last `true` condition?
227
+ end
228
+ end
229
+ end
230
+
231
+ def spawn_source_task(run, num_tasks)
84
232
  pending_sources = nil
85
233
  @source_cache.each_value do |source_by_batch_params|
86
234
  source_by_batch_params.each_value do |source|
@@ -92,18 +240,29 @@ module GraphQL
92
240
  end
93
241
 
94
242
  if pending_sources
243
+ if num_tasks == Float::INFINITY
244
+ num_tasks = pending_sources.size
245
+ end
95
246
  fiber_vars = get_fiber_variables
96
- parent_task.async do
97
- trace&.dataloader_spawn_source_fiber(pending_sources)
98
- set_fiber_variables(fiber_vars)
99
- Fiber[:graphql_dataloader_next_tick] = condition
100
- pending_sources.each do |s|
101
- trace&.begin_dataloader_source(s)
102
- s.run_pending_keys
103
- trace&.end_dataloader_source(s)
247
+ trace = run.trace
248
+ num_tasks.times do
249
+ run.root_task.async do |task|
250
+ Fiber[:__graphql_async_dataloader_run] = run
251
+ Fiber[:__graphql_async_dataloader_condition] = run.snoozed_sources_condition
252
+ trace&.dataloader_spawn_source_fiber(pending_sources)
253
+ set_fiber_variables(fiber_vars)
254
+ run.started_tasks.push(task)
255
+ while (source = pending_sources.shift)
256
+ trace&.begin_dataloader_source(source)
257
+ source.run_pending_keys
258
+ trace&.end_dataloader_source(source)
259
+ end
260
+ nil
261
+ ensure
262
+ run.finished_tasks.push($! || task)
263
+ cleanup_fiber
264
+ trace&.dataloader_fiber_exit
104
265
  end
105
- cleanup_fiber
106
- trace&.dataloader_fiber_exit
107
266
  end
108
267
  end
109
268
  end
@@ -51,9 +51,9 @@ module GraphQL
51
51
  def value
52
52
  query = @selections_step.query
53
53
  set_current_field
54
- query.current_trace.begin_execute_field(@field_definition, @arguments, @field_results, query)
54
+ query.current_trace.begin_execute_field(@field_definition, @field_results, @arguments, query)
55
55
  sync(@field_results)
56
- query.current_trace.end_execute_field(@field_definition, @arguments, @field_results, query, @field_results)
56
+ query.current_trace.end_execute_field(@field_definition, @field_results, @arguments, query, @field_results)
57
57
  @runner.add_step(self)
58
58
  true
59
59
  ensure
@@ -244,7 +244,7 @@ module GraphQL
244
244
  @was_scoped = true
245
245
  end
246
246
 
247
- query.current_trace.begin_execute_field(@field_definition, @arguments, authorized_objects, query)
247
+ query.current_trace.begin_execute_field(@field_definition, authorized_objects, @arguments, query)
248
248
 
249
249
  if @runner.uses_runtime_directives
250
250
  if @ast_nodes.nil? || @ast_nodes.size == 1
@@ -319,7 +319,7 @@ module GraphQL
319
319
  @field_results = resolve_batch(authorized_objects, ctx, @arguments)
320
320
  end
321
321
 
322
- query.current_trace.end_execute_field(@field_definition, @arguments, authorized_objects, query, @field_results)
322
+ query.current_trace.end_execute_field(@field_definition, authorized_objects, @arguments, query, @field_results)
323
323
 
324
324
  if any_lazy_results?
325
325
  @runner.dataloader.lazy_at_depth(path.size, self)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.6.3"
3
+ VERSION = "2.6.4"
4
4
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.3
4
+ version: 2.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-05-26 00:00:00.000000000 Z
10
+ date: 2026-06-22 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: base64