Module: AsyncAware

Extended by:
ActiveSupport::Concern
Included in:
Application
Defined in:
app/models/async_aware.rb

Overview

Prototype support for simple parallel requests. It is the callers responsibility to ensure that blocks are side-effect free.

Defined Under Namespace

Classes: ThreadTimedOut

Instance Method Summary collapse

Instance Method Details

#async(&block) ⇒ Object



8
9
10
11
12
13
14
15
16
# File 'app/models/async_aware.rb', line 8

def async(&block)
  (@threads ||= []) << Thread.start do
    begin
      Thread.current[:out] = yield block
    rescue => e
      Thread.current[:out] = e
    end
  end
end

#join(limit = nil) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'app/models/async_aware.rb', line 17

def join(limit=nil)
  running = @threads
  t1 = Time.now.to_i

  threads = begin
    @threads.map{ |t| limit ? t.join(limit) : t.join }
  ensure
    @threads.each(&:kill)
    @threads = nil
  end

  #puts                  "**** Joined #{Time.now.to_i - t1} (limit=#{limit})"
  #puts running.map{ |t| "     #{t.inspect}: #{threads.include?(t) ? "" : "(did not finish) "}#{t[:out].inspect}" }.join("\n")

  running.map do |t| 
    if threads.include?(t) 
      t[:out]
    else
      begin; raise(ThreadTimedOut.new(t, limit)); rescue => e; e; end
    end
  end
end

#join!(limit = nil) ⇒ Object

Throw the first exception encountered



43
44
45
46
47
48
49
# File 'app/models/async_aware.rb', line 43

def join!(limit=nil)
  join(limit).tap do |results|
    exceptions = results.select{ |r| r.is_a? StandardError }
    exceptions[1..-1].each{ |e| Rails.logger.error "#{e.class} (#{e})\n  #{Rails.backtrace_cleaner.clean(e.backtrace).join("\n  ")}" } if exceptions.size > 1
    raise exceptions.first unless exceptions.empty?
  end
end