ActionPool 0.0.1

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