Module: Puppeteer::AsyncUtils

Extended by:
AsyncUtils
Included in:
AsyncUtils
Defined in:
lib/puppeteer/async_utils.rb

Overview

Async helpers for Promise-style coordination using socketry/async.

Defined Under Namespace

Classes: ImmediateTask

Instance Method Summary collapse

Instance Method Details

#async_timeout(timeout_ms, task = nil) {|async_task| ... } ⇒ Async::Task

Execute a task with a timeout using Async::Task#with_timeout.

Parameters:

  • timeout_ms (Numeric)

    Timeout duration in milliseconds (0 means no timeout)

  • task (Proc, Async::Promise, nil) (defaults to: nil)

    Task to execute; falls back to block

Yields:

  • (async_task)

    Execute a task within the timeout, optionally receiving Async::Task

Returns:

  • (Async::Task)

    Async task that resolves/rejects once the operation completes



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/puppeteer/async_utils.rb', line 35

def async_timeout(timeout_ms, task = nil, &block)
  if task
    runner = lambda do |async_task|
      if timeout_ms == 0
        if task.is_a?(Proc)
          args = task.arity.positive? ? [async_task] : []
          task.call(*args)
        else
          await(task)
        end
      else
        timeout_seconds = timeout_ms / 1000.0
        async_task.with_timeout(timeout_seconds) do
          if task.is_a?(Proc)
            args = task.arity.positive? ? [async_task] : []
            task.call(*args)
          else
            await(task)
          end
        end
      end
    end
  elsif block
    runner = lambda do |async_task|
      if timeout_ms == 0
        args = block.arity.positive? ? [async_task] : []
        await(block.call(*args))
      else
        timeout_seconds = timeout_ms / 1000.0
        async_task.with_timeout(timeout_seconds) do
          args = block.arity.positive? ? [async_task] : []
          await(block.call(*args))
        end
      end
    end
  else
    raise ArgumentError.new("AsyncUtils.async_timeout requires a task or block")
  end

  current_task = Async::Task.current?
  if current_task
    return current_task.async do |async_task|
      runner.call(async_task)
    end
  end

  result = nil
  error = nil
  Async do |async_task|
    result = runner.call(async_task)
  rescue => err
    error = err
  end.wait

  ImmediateTask.new(result, error)
end

#await(task) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/puppeteer/async_utils.rb', line 12

def await(task)
  if task.is_a?(Proc)
    task.call
  elsif task.is_a?(Async::Promise)
    current_task = Async::Task.current?
    if current_task
      until task.resolved?
        current_task.sleep(0.001)
      end
    end
    task.wait
  elsif task.respond_to?(:wait)
    task.wait
  else
    task
  end
end

#await_promise_all(*tasks) ⇒ Object

Wait for all async tasks to complete and return results.



93
94
95
# File 'lib/puppeteer/async_utils.rb', line 93

def await_promise_all(*tasks)
  Sync { zip(*tasks) }
end

#await_promise_race(*tasks) ⇒ Object

Race multiple async tasks and return the result of the first one to complete.



98
99
100
# File 'lib/puppeteer/async_utils.rb', line 98

def await_promise_race(*tasks)
  Sync { first(*tasks) }
end

#future_with_logging(&block) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/puppeteer/async_utils.rb', line 102

def future_with_logging(&block)
  proc do |*block_args|
    block.call(*block_args)
  rescue ::Puppeteer::TimeoutError
    raise
  rescue => err
    warn("#{err.message} (#{err.class})")
    raise err
  end
end

#sleep_seconds(duration) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/puppeteer/async_utils.rb', line 113

def sleep_seconds(duration)
  task = Async::Task.current
  if task
    task.sleep(duration)
  else
    Kernel.sleep(duration)
  end
rescue RuntimeError, NoMethodError
  Kernel.sleep(duration)
end