robustthread 0.3 → 0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. data/lib/robustthread.rb +41 -45
  2. metadata +2 -2
data/lib/robustthread.rb CHANGED
@@ -1,37 +1,6 @@
1
1
  # Author:: Jared Kuolt (mailto:me@superjared.com)
2
2
  # Copyright:: Copyright (c) 2009 Jared Kuolt
3
3
  # License:: MIT License
4
- #
5
- # This module allows for the creation of a thread that will not simply die when
6
- # the process dies. Instead, it joins all RobustThreads in Ruby's exit handler.
7
- #
8
- # Usage:
9
- #
10
- # rt = RobustThread.new(args) do |x, y|
11
- # do_something(x, y)
12
- # end
13
- #
14
- # If necessary, you can access the actual thread from the RobustThread
15
- # object via its +thread+ attribute.
16
- #
17
- # rt.thread
18
- # => #<Thread:0x7fa1ea57ff88 run>
19
- #
20
- # By default, RobustThread uses a Logger that defaults itself to STDOUT. You
21
- # can change this by assigning the +logger+ class attribute to a different
22
- # Logger object:
23
- #
24
- # RobustThread.logger = Logger.new(STDERR)
25
- #
26
- # Since Threads usually eat exceptions, RobustThread allows for a simple global
27
- # exception handler:
28
- #
29
- # RobustThread.exception_handler do |exception|
30
- # # Handle your exceptions here
31
- # end
32
- #
33
- # If no handler is assigned, the exception traceback will be piped into the
34
- # logger as an error message.
35
4
  require 'logger'
36
5
 
37
6
  class RobustThread
@@ -39,10 +8,13 @@ class RobustThread
39
8
  attr_reader :thread
40
9
  # If the Thread takes a poopie...
41
10
  attr_reader :exception
11
+ # An identifier
12
+ attr_accessor :label
42
13
 
43
- # Create a new RobustThread (see usage)
44
- def initialize(*args, &block)
14
+ # Create a new RobustThread (see README)
15
+ def initialize(opts={}, &block)
45
16
  self.class.send :init_exit_handler
17
+ args = opts[:args] or []
46
18
  @thread = Thread.new(*args) do |*targs|
47
19
  begin
48
20
  block.call(*targs)
@@ -50,19 +22,43 @@ class RobustThread
50
22
  @exception = e
51
23
  self.class.send :handle_exception, e
52
24
  end
25
+ self.class.log "#{self.label.inspect} exited cleanly"
53
26
  end
54
- @thread[:real_ultimate_power] = true
27
+ self.label = opts[:label] || @thread.inspect
28
+ self.class.group << self
55
29
  end
56
30
 
57
31
  ## Class methods and attributes
58
32
  class << self
59
- attr_accessor :logger, :exit_handler_initialized
33
+ attr_accessor :logger, :say_goodnight, :exit_handler_initialized
60
34
 
61
- # Logger object (see usage)
35
+ # Logger object (see README)
62
36
  def logger
63
37
  @logger ||= Logger.new(STDOUT)
64
38
  end
65
39
 
40
+ # Simple log interface
41
+ def log(msg, level=:info)
42
+ self.logger.send level, "#{self}: " + msg
43
+ end
44
+
45
+ # The collection of RobustThread objects
46
+ def group
47
+ @group ||= []
48
+ end
49
+
50
+ # Loop an activity and exit it cleanly (see README)
51
+ def loop(opts={}, &block)
52
+ sleep_seconds = opts.delete(:seconds) || 2
53
+ self.new(opts) do |*args|
54
+ Kernel.loop do
55
+ break if self.say_goodnight
56
+ block.call(*args)
57
+ sleep sleep_seconds
58
+ end
59
+ end
60
+ end
61
+
66
62
  # Set exception handler
67
63
  def exception_handler(&block)
68
64
  unless block.arity == 1
@@ -77,25 +73,25 @@ class RobustThread
77
73
  if @exception_handler.is_a? Proc
78
74
  @exception_handler.call(exc)
79
75
  else
80
- self.logger.error("RobustThread: Unhandled exception:\n#{exc.message} " \
81
- "(#{exc.class}): \n\t#{exc.backtrace.join("\n\t")}")
76
+ log("Unhandled exception:\n#{exc.message} " \
77
+ "(#{exc.class}): \n\t#{exc.backtrace.join("\n\t")}", :error)
82
78
  end
83
79
  end
84
80
 
85
81
  # Sets up the exit_handler unless exit_handler_initialized
86
82
  def init_exit_handler
87
83
  return if self.exit_handler_initialized
84
+ self.say_goodnight = false
88
85
  at_exit do
86
+ self.say_goodnight = true
89
87
  begin
90
- Thread.list.each do |thread|
91
- if thread[:real_ultimate_power]
92
- logger.info "RobustThread waiting on #{thread.inspect}"
93
- thread.join
94
- end
88
+ self.group.each do |rt|
89
+ log "waiting on #{rt.label.inspect}"
90
+ rt.thread.join
95
91
  end
96
- logger.info "RobustThread exited cleanly"
92
+ log "exited cleanly"
97
93
  rescue Interrupt
98
- logger.error "RobustThread(s) prematurely killed by interrupt!"
94
+ log "prematurely killed by interrupt!", :error
99
95
  end
100
96
  end
101
97
  self.exit_handler_initialized = true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robustthread
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.3"
4
+ version: "0.4"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared Kuolt
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-05 00:00:00 -07:00
12
+ date: 2009-06-08 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15