Class: Desiru::GraphQL::DataLoader::Promise

Inherits:
Object
  • Object
show all
Defined in:
lib/desiru/graphql/data_loader.rb

Overview

Thread-safe Promise implementation for lazy loading

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ Promise

Returns a new instance of Promise.



285
286
287
288
289
290
291
292
293
# File 'lib/desiru/graphql/data_loader.rb', line 285

def initialize(&block)
  @mutex = Mutex.new
  @condition = ConditionVariable.new
  @fulfilled = false
  @value = nil
  @error = nil
  @callbacks = []
  block&.call(self)
end

Instance Method Details

#fulfill(value) ⇒ Object



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/desiru/graphql/data_loader.rb', line 295

def fulfill(value)
  callbacks_to_run = nil

  @mutex.synchronize do
    return if @fulfilled

    @value = value
    @fulfilled = true
    callbacks_to_run = @callbacks.dup
    @callbacks.clear

    # Signal all waiting threads
    @condition.broadcast
  end

  # Run callbacks outside the mutex to avoid deadlock
  callbacks_to_run&.each { |cb| cb.call(value) }
end

#fulfilled?Boolean

Returns:

  • (Boolean)


367
368
369
# File 'lib/desiru/graphql/data_loader.rb', line 367

def fulfilled?
  @mutex.synchronize { @fulfilled }
end

#reject(error) ⇒ Object



314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/desiru/graphql/data_loader.rb', line 314

def reject(error)
  @mutex.synchronize do
    return if @fulfilled

    @error = error
    @fulfilled = true
    @callbacks.clear

    # Signal all waiting threads
    @condition.broadcast
  end
end

#rejected?Boolean

Returns:

  • (Boolean)


371
372
373
# File 'lib/desiru/graphql/data_loader.rb', line 371

def rejected?
  @mutex.synchronize { @fulfilled && !@error.nil? }
end

#then(&block) ⇒ Object



327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/desiru/graphql/data_loader.rb', line 327

def then(&block)
  run_immediately = false
  value_to_pass = nil

  @mutex.synchronize do
    if @fulfilled && !@error
      run_immediately = true
      value_to_pass = @value
    elsif !@fulfilled
      @callbacks << block
    end
  end

  # Run callback outside mutex if already fulfilled
  block.call(value_to_pass) if run_immediately

  self
end

#value(timeout: nil) ⇒ Object



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/desiru/graphql/data_loader.rb', line 346

def value(timeout: nil)
  @mutex.synchronize do
    if timeout
      end_time = Time.now + timeout
      until @fulfilled
        remaining = end_time - Time.now
        break if remaining <= 0

        @condition.wait(@mutex, remaining)
      end
    else
      @condition.wait(@mutex) until @fulfilled
    end

    raise @error if @error
    raise "Promise not yet fulfilled" unless @fulfilled

    @value
  end
end