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]

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)



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

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 => 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.



37
38
39
# File 'lib/robustthread.rb', line 37

def callbacks
  @callbacks
end

.exit_handler_initializedObject

Returns the value of attribute exit_handler_initialized.



37
38
39
# File 'lib/robustthread.rb', line 37

def exit_handler_initialized
  @exit_handler_initialized
end

.loggerObject

Logger object (see README)



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

def logger
  @logger
end

.say_goodnightObject

Returns the value of attribute say_goodnight.



37
38
39
# File 'lib/robustthread.rb', line 37

def say_goodnight
  @say_goodnight
end

Instance Attribute Details

#exceptionObject (readonly)

If the Thread takes a poopie…



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

def exception
  @exception
end

#labelObject

An identifier



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

def label
  @label
end

#threadObject (readonly)

The Thread object, brah



9
10
11
# File 'lib/robustthread.rb', line 9

def thread
  @thread
end

Class Method Details

.add_callback(sym, &block) ⇒ Object

Raises:

  • (ArgumentError)


91
92
93
94
95
96
97
# File 'lib/robustthread.rb', line 91

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



82
83
84
85
86
87
# File 'lib/robustthread.rb', line 82

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



51
52
53
# File 'lib/robustthread.rb', line 51

def group
  @group ||= [] 
end

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

Simple log interface



46
47
48
# File 'lib/robustthread.rb', line 46

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)



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

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