Class: RobustThread

Inherits:
Object
  • Object
show all
Defined in:
lib/robustthread.rb

Constant Summary collapse

VALID_CALLBACKS =
[:before_init, :before_yield, :after_yield, :after_join, :before_exit]

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}, &block) ⇒ RobustThread

Create a new RobustThread (see README)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/robustthread.rb', line 19

def initialize(opts={}, &block)
  self.class.send :init_exit_handler
  args = opts[:args] or []
  self.class.send :do_before_init
  @thread = Thread.new(*args) do |*targs|
    begin
      self.class.send :do_before_yield
      block.call(*targs)
      self.class.send :do_after_yield
    rescue Exception => e
      @exception = e
      self.class.send :handle_exception, e
    end
    self.class.log "#{self.label.inspect} exited cleanly"
  end
  self.label = opts[:label] || @thread.inspect
  self.class.group << self
end

Class Attribute Details

.callbacksObject

Returns the value of attribute callbacks


40
41
42
# File 'lib/robustthread.rb', line 40

def callbacks
  @callbacks
end

.exit_handler_initializedObject

Returns the value of attribute exit_handler_initialized


40
41
42
# File 'lib/robustthread.rb', line 40

def exit_handler_initialized
  @exit_handler_initialized
end

.loggerObject

Logger object (see README)


44
45
46
# File 'lib/robustthread.rb', line 44

def logger
  @logger
end

.say_goodnightObject

Returns the value of attribute say_goodnight


40
41
42
# File 'lib/robustthread.rb', line 40

def say_goodnight
  @say_goodnight
end

Instance Attribute Details

#exceptionObject (readonly)

If the Thread takes a poopie…


14
15
16
# File 'lib/robustthread.rb', line 14

def exception
  @exception
end

#labelObject

An identifier


16
17
18
# File 'lib/robustthread.rb', line 16

def label
  @label
end

#threadObject (readonly)

The Thread object, brah


12
13
14
# File 'lib/robustthread.rb', line 12

def thread
  @thread
end

Class Method Details

.add_callback(sym, &block) ⇒ Object

Raises:

  • (ArgumentError)

94
95
96
97
98
99
100
# File 'lib/robustthread.rb', line 94

def add_callback(sym, &block)
  sym = sym.to_sym
  raise ArgumentError, "Invalid callback #{sym.inspect}" unless VALID_CALLBACKS.include? sym
  self.callbacks ||= {}
  self.callbacks[sym] ||= []
  self.callbacks[sym] << block
end

.exception_handler(&block) ⇒ Object

Set exception handler


85
86
87
88
89
90
# File 'lib/robustthread.rb', line 85

def exception_handler(&block)
  unless block.arity == 1
    raise ArgumentError, "Bad arity for exception handler. It may only accept a single argument"
  end
  @exception_handler = block
end

.groupObject

The collection of RobustThread objects


54
55
56
# File 'lib/robustthread.rb', line 54

def group
  @group ||= [] 
end

.log(msg, level = :info) ⇒ Object

Simple log interface


49
50
51
# File 'lib/robustthread.rb', line 49

def log(msg, level=:info)
  self.logger.send level, "#{self}: " + msg
end

.loop(opts = {}, &block) ⇒ Object

Loop an activity and exit it cleanly (see README)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/robustthread.rb', line 59

def loop(opts={}, &block)
  sleep_seconds = opts.delete(:seconds) || 2
  self.new(opts) do |*args|
    Kernel.loop do
      break if self.say_goodnight
      block.call(*args)
      # We want to sleep for the right amount of time, but we also don't
      # want to wait until the sleep is done if our exit handler has been
      # called so we iterate over a loop, sleeping only 0.1 and checking
      # each iteration whether we need to die, and the timeout is a noop
      # indicating we need to continue.
      begin
        Timeout.timeout(sleep_seconds) do
          Kernel.loop do
            break if self.say_goodnight
            sleep 0.1
          end
        end
      rescue Timeout::Error
        # OK
      end
    end
  end
end