robustthread 0.2 → 0.3

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 +77 -41
  2. metadata +2 -2
data/lib/robustthread.rb CHANGED
@@ -1,68 +1,104 @@
1
- # This module allows for the creation of a thread that will not simply die when
2
- # the process dies. Instead, it joins all RobustThreads in Ruby's exit handler.
3
- #
4
1
  # Author:: Jared Kuolt (mailto:me@superjared.com)
5
2
  # Copyright:: Copyright (c) 2009 Jared Kuolt
6
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
+ require 'logger'
7
36
 
8
37
  class RobustThread
9
38
  # The Thread object, brah
10
39
  attr_reader :thread
11
40
  # If the Thread takes a poopie...
12
41
  attr_reader :exception
13
- @@exit_handler_initialized = false
14
- @@exception_handler = nil
15
- # Usage:
16
- #
17
- # rt = RobustThread.new(args) do |x, y|
18
- # do_something(x, y)
19
- # end
20
- #
21
- # If necessary, you can access the actual thread from the +RobustThread+
22
- # object via its +thread+ attribute.
23
- #
24
- # rt.thread
25
- # => #<Thread:0x7fa1ea57ff88 run>
42
+
43
+ # Create a new RobustThread (see usage)
26
44
  def initialize(*args, &block)
27
- RobustThread.init_exit_handler
45
+ self.class.send :init_exit_handler
28
46
  @thread = Thread.new(*args) do |*targs|
29
47
  begin
30
48
  block.call(*targs)
31
49
  rescue => e
32
50
  @exception = e
33
- RobustThread.handle_exception(e)
51
+ self.class.send :handle_exception, e
34
52
  end
35
53
  end
36
54
  @thread[:real_ultimate_power] = true
37
55
  end
38
56
 
39
- # Set exception handler:
40
- #
41
- # RobustThread.exception_handler do |exception|
42
- # handle_exception(exception)
43
- # end
44
- def RobustThread.exception_handler(&block)
45
- unless block.arity == 1
46
- raise ArgumentError, "Bad arity for exception handler. It may only accept a single argument"
57
+ ## Class methods and attributes
58
+ class << self
59
+ attr_accessor :logger, :exit_handler_initialized
60
+
61
+ # Logger object (see usage)
62
+ def logger
63
+ @logger ||= Logger.new(STDOUT)
47
64
  end
48
- @@exception_handler = block
49
- end
50
65
 
51
- private
52
- # Sets up the exit_handler unless @@exit_handler_initialized
53
- def RobustThread.init_exit_handler
54
- return if @@exit_handler_initialized
55
- at_exit do
56
- Thread.list.each do |thread|
57
- thread.join if thread[:real_ultimate_power]
66
+ # Set exception handler
67
+ def exception_handler(&block)
68
+ unless block.arity == 1
69
+ raise ArgumentError, "Bad arity for exception handler. It may only accept a single argument"
70
+ end
71
+ @exception_handler = block
72
+ end
73
+
74
+ private
75
+ # Calls exception handler if set (see RobustThread.exception_handler)
76
+ def handle_exception(exc)
77
+ if @exception_handler.is_a? Proc
78
+ @exception_handler.call(exc)
79
+ else
80
+ self.logger.error("RobustThread: Unhandled exception:\n#{exc.message} " \
81
+ "(#{exc.class}): \n\t#{exc.backtrace.join("\n\t")}")
58
82
  end
59
83
  end
60
- @@exit_handler_initialized = true
61
- end
62
84
 
63
- # Calls exception handler if set (see RobustThread.exception_handler)
64
- def RobustThread.handle_exception(exception)
65
- return unless @@exception_handler
66
- @@exception_handler.call(exception)
85
+ # Sets up the exit_handler unless exit_handler_initialized
86
+ def init_exit_handler
87
+ return if self.exit_handler_initialized
88
+ at_exit do
89
+ 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
95
+ end
96
+ logger.info "RobustThread exited cleanly"
97
+ rescue Interrupt
98
+ logger.error "RobustThread(s) prematurely killed by interrupt!"
99
+ end
100
+ end
101
+ self.exit_handler_initialized = true
102
+ end
67
103
  end
68
104
  end
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.2"
4
+ version: "0.3"
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-03 00:00:00 -07:00
12
+ date: 2009-06-05 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15