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.
- data/lib/robustthread.rb +41 -45
- 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
|
44
|
-
def initialize(
|
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
|
-
|
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
|
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
|
-
|
81
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
92
|
+
log "exited cleanly"
|
97
93
|
rescue Interrupt
|
98
|
-
|
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.
|
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-
|
12
|
+
date: 2009-06-08 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|