ActionPool 0.0.1

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.
File without changes
data/README ADDED
@@ -0,0 +1,40 @@
1
+ == ActionPool ==
2
+ ~Who doesn't love a pool with action?~
3
+
4
+ ActionPool is just a simple thread pool. It allows
5
+ for various contraints and resizing in a pretty
6
+ easy and unobtrusive manner. You can set limits
7
+ on how long tasks are worked on, as well as on the
8
+ life of a thread. For things that like to use lots
9
+ threads, it can be helpful to reuse threads instead of
10
+ constantly recreating them.
11
+
12
+ install (easy):
13
+
14
+ gem install ActionPool
15
+
16
+ install (less easy):
17
+
18
+ git clone http://github.com/spox/actionpool.git
19
+ cd actionpool
20
+ gem build actionpool.gemspec
21
+ gem install ActionPool-x.x.x.gem
22
+
23
+ It has RDocs. They are where ever your rubygems installed them.
24
+ They will probably be helpful to look over.
25
+
26
+ Simple example of using the pool:
27
+
28
+ pool = ActionPool::Pool.new
29
+ pool.process do
30
+ puts "Hello world"
31
+ sleep(1)
32
+ puts "Goodbye world"
33
+ end
34
+ puts "Hello to you too"
35
+
36
+ Result:
37
+ Hello world
38
+ Hello to you too
39
+ Goodbye world
40
+
@@ -0,0 +1,12 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'ActionPool'
3
+ s.author = %q(spox)
4
+ s.email = %q(spox@modspox.com)
5
+ s.version = '0.0.1'
6
+ s.summary = %q(Thread Pool)
7
+ s.platform = Gem::Platform::RUBY
8
+ s.has_rdoc = true
9
+ s.files = Dir['**/*']
10
+ s.require_paths = %w(lib)
11
+ s.required_ruby_version = '>= 1.8.6'
12
+ end
@@ -0,0 +1,19 @@
1
+ module ActionPool
2
+
3
+ class InvalidType < Exception
4
+ attr_reader :given
5
+ attr_reader :expected
6
+ def initialize(g,e)
7
+ @given = given
8
+ @expected = e
9
+ end
10
+
11
+ def to_s
12
+ "Given type: #{g} Expected type: #{e}"
13
+ end
14
+ end
15
+
16
+ class InvalidValue < Exception
17
+ end
18
+
19
+ end
@@ -0,0 +1,26 @@
1
+ require 'logger'
2
+
3
+ module ActionPool
4
+ class LogHelper
5
+
6
+ def initialize(logger=nil)
7
+ @logger = logger
8
+ end
9
+
10
+ def info(m)
11
+ @logger.info(m) unless @logger.nil?
12
+ end
13
+
14
+ def warn(m)
15
+ @logger.warn(m) unless @logger.nil?
16
+ end
17
+
18
+ def fatal(m)
19
+ @logger.fatal(m) unless @logger.nil?
20
+ end
21
+
22
+ def error(m)
23
+ @logger.error(m) unless @logger.nil?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,158 @@
1
+ require 'actionpool/Exceptions'
2
+ require 'actionpool/Thread'
3
+ require 'actionpool/LogHelper'
4
+ require 'thread'
5
+
6
+ module ActionPool
7
+ class Pool
8
+
9
+ # min_threads:: minimum number of threads in pool
10
+ # max_threads:: maximum number of threads in pool
11
+ # t_to:: thread timeout waiting for action to process
12
+ # a_to:: maximum time action may be worked on before aborting
13
+ # logger:: logger to print logging messages to
14
+ # Creates a new pool
15
+ def initialize(min_threads=10, max_threads=100, t_to=60, a_to=nil, logger=nil)
16
+ @logger = LogHelper.new(logger)
17
+ @queue = Queue.new
18
+ @threads = []
19
+ @lock = Mutex.new
20
+ @thread_timeout = t_to
21
+ @action_timeout = a_to
22
+ @min_threads = min_threads
23
+ @max_threads = max_threads
24
+ @min_threads.times{create_thread}
25
+ end
26
+
27
+ # force:: force creation of a new thread
28
+ # Create a new thread for pool
29
+ def create_thread(force=false)
30
+ return nil unless @threads.size < @max_threads || force
31
+ @logger.info('Pool is creating a new thread')
32
+ pt = ActionPool::Thread.new(self, @thread_timeout, @action_timeout, @logger)
33
+ @threads << pt
34
+ return pt
35
+ end
36
+
37
+ # force:: force immediate stop
38
+ # Stop the pool
39
+ def shutdown(force=false)
40
+ @logger.info("Pool is now shutting down #{force ? 'using force' : ''}")
41
+ @threads.each{|t|t.stop}
42
+ until(size < 1) do
43
+ @queue << lambda{}
44
+ sleep(0.1)
45
+ end
46
+ end
47
+
48
+ # action:: proc to be executed
49
+ # Add a new proc/lambda to be executed (alias for queue)
50
+ def <<(action)
51
+ queue(action)
52
+ end
53
+
54
+ # action:: proc to be executed
55
+ # Add a new proc/lambda to be executed
56
+ def queue(action)
57
+ raise InvalidType.new(action.class, Proc) unless action.is_a?(Proc)
58
+ @queue << action
59
+ start_thread if size > min
60
+ end
61
+
62
+ # block:: block to process
63
+ # Adds a block to be processed
64
+ def process(&block)
65
+ queue(block)
66
+ end
67
+
68
+ # Current size of pool
69
+ def size
70
+ @threads.size
71
+ end
72
+
73
+ # Maximum allowed number of threads
74
+ def max
75
+ @max_threads
76
+ end
77
+
78
+ # Minimum allowed number of threads
79
+ def min
80
+ @min_threads
81
+ end
82
+
83
+ # m:: new max
84
+ # Set maximum number of threads
85
+ def max=(m)
86
+ m = m.to_i
87
+ raise InvalidValue.new unless m > 0
88
+ @max_threads = m
89
+ end
90
+
91
+ # m:: new min
92
+ # Set minimum number of threads
93
+ def min=(m)
94
+ m = m.to_i
95
+ raise InvalidValue.new unless m > 0 && m <= @max_threads
96
+ @min_threads = m
97
+ resize if m < size
98
+ end
99
+
100
+ # t:: ActionPool::Thread to remove
101
+ # Removes a thread from the pool
102
+ def remove(t)
103
+ @threads.delete(t)
104
+ end
105
+
106
+ # Maximum number of seconds a thread
107
+ # is allowed to idle in the pool.
108
+ # (nil means thread life is infinite)
109
+ def thread_timeout
110
+ @thread_timeout
111
+ end
112
+
113
+ # Maximum number of seconds a thread
114
+ # is allowed to work on a given action
115
+ # (nil means thread is given unlimited
116
+ # time to work on action)
117
+ def action_timeout
118
+ @action_timeout
119
+ end
120
+
121
+ # t:: timeout in seconds (nil for infinite)
122
+ # Set maximum allowed time thead may idle in pool
123
+ def thread_timeout=(t)
124
+ t = to_i unless t.nil?
125
+ raise InvalidValue.new unless t > 0 || t.nil?
126
+ @thread_timeout = t
127
+ end
128
+
129
+ # t:: timeout in seconds (nil for infinte)
130
+ # Set maximum allowed time thread may work
131
+ # on a given action
132
+ def action_timeout=(t)
133
+ t = to_i unless t.nil?
134
+ raise InvalidValue.new unless t > 0 || t.nil?
135
+ @action_timeout = t
136
+ end
137
+
138
+ # Returns the next action to be processed
139
+ def action
140
+ @queue.pop
141
+ end
142
+
143
+ # Number of actions in the queue
144
+ def action_size
145
+ @queue.size
146
+ end
147
+
148
+ private
149
+
150
+ def resize
151
+ @logger.info("Pool is being resized to stated minimum: #{min}")
152
+ size - min.times do
153
+ t = @threads.shift
154
+ t.stop
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,71 @@
1
+ require 'timeout'
2
+
3
+ module ActionPool
4
+ class Thread
5
+ # pool:: pool thread is associated with
6
+ # t_timeout:: max time a thread is allowed to wait for action
7
+ # a_timeout:: max time thread is allowed to work
8
+ # logger:: LogHelper for logging messages
9
+ # Create a new thread
10
+ def initialize(pool, t_timeout, a_timeout, logger=nil)
11
+ @pool = pool
12
+ @pool_timeout = t_timeout.nil? ? 0 : t_timeout
13
+ @action_timeout = a_timeout.nil? ? 0 : a_timeout
14
+ @kill = false
15
+ @logger = logger
16
+ @thread = ::Thread.new{ start_thread }
17
+ end
18
+
19
+ # stop the thread
20
+ def stop(force=false)
21
+ @kill = true
22
+ @thread.kill if force
23
+ end
24
+
25
+ private
26
+
27
+ def start_thread
28
+ begin
29
+ @logger.info("New pool thread is starting (#{self})")
30
+ until(@kill) do
31
+ begin
32
+ action = nil
33
+ if(@pool.size > @pool.min)
34
+ Timeout::timeout(@thread_timeout) do
35
+ action = @pool.action
36
+ end
37
+ else
38
+ action = @pool.action
39
+ end
40
+ run(action) unless action.nil?
41
+ rescue Timeout::Error => boom
42
+ @kill = true
43
+ rescue Object => boom
44
+ @logger.error("Pool thread caught an exception: #{boom}\n#{boom.backtrace.join("\n")}")
45
+ end
46
+ end
47
+ rescue Object => boom
48
+ @logger.error("Pool thread caught an exception: #{boom}\n#{boom.backtrace.join("\n")}")
49
+ ensure
50
+ @logger.info("Pool thread is shutting down (#{self})")
51
+ @pool.remove(self)
52
+ end
53
+ end
54
+
55
+ def run(action)
56
+ begin
57
+ if(@action_timeout > 0)
58
+ Timeout::timeout(@action_timeout) do
59
+ action.call
60
+ end
61
+ else
62
+ action.call
63
+ end
64
+ rescue Timeout::Error => boom
65
+ @logger.warn("Pool thread reached max execution time for action: #{boom}")
66
+ rescue Object => boom
67
+ @logger.error("Pool thread caught an exception running action: #{boom}\n#{boom.backtrace.join("\n")}")
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/actionpool.rb ADDED
@@ -0,0 +1 @@
1
+ require 'actionpool/Pool'
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ActionPool
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - spox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: spox@modspox.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib
26
+ - lib/actionpool
27
+ - lib/actionpool/Exceptions.rb
28
+ - lib/actionpool/LogHelper.rb
29
+ - lib/actionpool/Pool.rb
30
+ - lib/actionpool/Thread.rb
31
+ - lib/actionpool.rb
32
+ - README
33
+ - ActionPool-0.0.1.gem
34
+ - actionpool.gemspec
35
+ has_rdoc: true
36
+ homepage:
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.8.6
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.3.0
58
+ signing_key:
59
+ specification_version: 2
60
+ summary: Thread Pool
61
+ test_files: []
62
+