robustthread 0.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|