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.
- data/lib/robustthread.rb +77 -41
- 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
|
-
|
14
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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.
|
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-
|
12
|
+
date: 2009-06-05 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|