opee 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -2
- data/lib/opee.rb +2 -0
- data/lib/opee/actor.rb +1 -1
- data/lib/opee/askqueue.rb +29 -0
- data/lib/opee/env.rb +0 -1
- data/lib/opee/queue.rb +94 -0
- data/lib/opee/version.rb +1 -1
- data/lib/opee/workqueue.rb +5 -66
- metadata +4 -3
- data/test/tests.rb +0 -40
data/README.md
CHANGED
@@ -24,9 +24,9 @@ Give it a try. Any comments, thoughts, or suggestions are welcome.
|
|
24
24
|
|
25
25
|
## <a name="release">Release Notes</a>
|
26
26
|
|
27
|
-
### Release 1.0.
|
27
|
+
### Release 1.0.2
|
28
28
|
|
29
|
-
-
|
29
|
+
- Added AskQueue which serves up method invocations instead of jobs.
|
30
30
|
|
31
31
|
# Plans and Notes
|
32
32
|
|
data/lib/opee.rb
CHANGED
data/lib/opee/actor.rb
CHANGED
@@ -158,7 +158,7 @@ module Opee
|
|
158
158
|
# @param [Array] args arguments to the op method
|
159
159
|
# @param [Proc] blk ignored
|
160
160
|
def method_missing(m, *args, &blk)
|
161
|
-
raise NoMethodError.new("
|
161
|
+
raise NoMethodError.new("undefined method '#{m}' for #{self.class}", m, args) unless respond_to?(m, true)
|
162
162
|
ask(m, *args)
|
163
163
|
end
|
164
164
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module Opee
|
3
|
+
# Implements a work queue Actor that will distribute method calls to Actors
|
4
|
+
# that volunteer to execute those methods. The primary use is to distribute
|
5
|
+
# work across multiple workers.
|
6
|
+
class AskQueue < Queue
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
super(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Queues an operation and arguments to be handed off to a worker when the worker is ready.
|
13
|
+
# @param [Symbol] op method to queue for the Actor
|
14
|
+
# @param [Array] args arguments to the op method
|
15
|
+
# @raise [BusyError] if the request queue does not become available in the {#ask_timeout} seconds
|
16
|
+
def add_method(op, *args)
|
17
|
+
ask(:add, Act.new(op, args))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Asks the worker to invoke the method of an Act Object.
|
23
|
+
def ask_worker(worker, job)
|
24
|
+
raise NoMethodError.new("undefined method for #{job.class}. Expected a method invocation") unless job.is_a?(Actor::Act)
|
25
|
+
worker.ask(job.op, *job.args)
|
26
|
+
end
|
27
|
+
|
28
|
+
end # AskQueue
|
29
|
+
end # Opee
|
data/lib/opee/env.rb
CHANGED
data/lib/opee/queue.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
|
2
|
+
module Opee
|
3
|
+
# Implements a queue Actor that will distribute jobs to Actors that
|
4
|
+
# volunteer to complete those jobs. The primary use is to distribute work or
|
5
|
+
# jobs across multiple workers.
|
6
|
+
class Queue < Actor
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@workers = []
|
10
|
+
@work_queue = []
|
11
|
+
@max_job_count = 0
|
12
|
+
@job_timeout = 3.0
|
13
|
+
@add_thread = nil
|
14
|
+
super(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the number of jobs currently on the work queue.
|
18
|
+
# @return [Fixnum] number of waiting jobs
|
19
|
+
def work_queue_size()
|
20
|
+
@work_queue.size
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the number of worker Actors waiting to process jobs.
|
24
|
+
# @return [Fixnum] number of waiting workers
|
25
|
+
def worker_count()
|
26
|
+
@workers.size
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the true if any requests are queued, a request is being
|
30
|
+
# processed, or if there are jobs waiting on the work request queue.
|
31
|
+
# @return [true|false] true if busy, false otherwise
|
32
|
+
def busy?
|
33
|
+
!@work_queue.empty? || super
|
34
|
+
end
|
35
|
+
|
36
|
+
# Verifies that additional jobs can be added to the work queue before
|
37
|
+
# allowing an {#add}() to be called.
|
38
|
+
# @see Actor#ask
|
39
|
+
def ask(op, *args)
|
40
|
+
if :add == op && 0 < @max_job_count && (@work_queue.size() + @queue.size()) >= @max_job_count
|
41
|
+
unless 0.0 >= @job_timeout
|
42
|
+
@add_thread = Thread.current
|
43
|
+
give_up_at = Time.now + @job_timeout
|
44
|
+
until Time.now > give_up_at || (@work_queue.size() + @queue.size()) < @max_job_count
|
45
|
+
sleep(@job_timeout)
|
46
|
+
end
|
47
|
+
@add_thread = nil
|
48
|
+
end
|
49
|
+
raise BusyError.new() unless @work_queue.size() < @max_job_count
|
50
|
+
end
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Processes the initialize() options. Subclasses should call super.
|
57
|
+
# @param [Hash] options options to be used for initialization
|
58
|
+
# @option options [Symbol] :method method to call on workers
|
59
|
+
# @option options [Fixnum] :max_job_count maximum number of jobs
|
60
|
+
# that can be queued before backpressure is applied to the caller.
|
61
|
+
# @option options [Float] :job_timeout timeout in seconds to wait
|
62
|
+
# before raising a BusyError if the work queue is too long.
|
63
|
+
def set_options(options)
|
64
|
+
super(options)
|
65
|
+
@max_job_count = options.fetch(:max_job_count, @max_job_count)
|
66
|
+
@job_timeout = options.fetch(:job_timeout, @job_timeout)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Places a job on the work queue. This method is executed asynchronously.
|
70
|
+
# @param [Object] job work to be processed
|
71
|
+
def add(job)
|
72
|
+
if @workers.empty?
|
73
|
+
@work_queue.insert(0, job)
|
74
|
+
else
|
75
|
+
worker = @workers.pop()
|
76
|
+
ask_worker(worker, job)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Identifies a worker as available to process jobs when they become
|
81
|
+
# available. This method is executed asynchronously.
|
82
|
+
# @param [Actor] worker Actor that responds to the {#method}
|
83
|
+
def ready(worker)
|
84
|
+
if @work_queue.empty?
|
85
|
+
@workers.insert(0, worker) unless @workers.include?(worker)
|
86
|
+
else
|
87
|
+
job = @work_queue.pop()
|
88
|
+
@add_thread.wakeup() unless @add_thread.nil?
|
89
|
+
ask_worker(worker, job)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end # Queue
|
94
|
+
end # Opee
|
data/lib/opee/version.rb
CHANGED
data/lib/opee/workqueue.rb
CHANGED
@@ -1,26 +1,15 @@
|
|
1
1
|
|
2
2
|
module Opee
|
3
|
-
# Implements a work queue Actor that
|
3
|
+
# Implements a work queue Actor that will distribute jobs to Actors that
|
4
4
|
# volunteer to complete those jobs. The primary use is to distribute work or
|
5
5
|
# jobs across multiple workers.
|
6
|
-
class WorkQueue <
|
6
|
+
class WorkQueue < Queue
|
7
7
|
|
8
8
|
def initialize(options={})
|
9
|
-
@workers = []
|
10
|
-
@work_queue = []
|
11
9
|
@method = nil
|
12
|
-
@max_job_count = 0
|
13
|
-
@job_timeout = 3.0
|
14
|
-
@add_thread = nil
|
15
10
|
super(options)
|
16
11
|
end
|
17
12
|
|
18
|
-
# Returns the number of jobs currently on the work queue.
|
19
|
-
# @return [Fixnum] number of waiting jobs
|
20
|
-
def work_queue_size()
|
21
|
-
@work_queue.size
|
22
|
-
end
|
23
|
-
|
24
13
|
# Returns the number of worker Actors waiting to process jobs.
|
25
14
|
# @return [Fixnum] number of waiting workers
|
26
15
|
def worker_count()
|
@@ -33,69 +22,19 @@ module Opee
|
|
33
22
|
@workers.size
|
34
23
|
end
|
35
24
|
|
36
|
-
# Returns the true if any requests are queued, a request is being
|
37
|
-
# processed, or if there are jobs waiting on the work request queue.
|
38
|
-
# @return [true|false] true if busy, false otherwise
|
39
|
-
def busy?
|
40
|
-
!@work_queue.empty? || super
|
41
|
-
end
|
42
|
-
|
43
|
-
# Verifies that additional jobs can be added to the work queue before
|
44
|
-
# allowing an {#add}() to be called.
|
45
|
-
# @see Actor#ask
|
46
|
-
def ask(op, *args)
|
47
|
-
if :add == op && 0 < @max_job_count && (@work_queue.size() + @queue.size()) >= @max_job_count
|
48
|
-
unless 0.0 >= @job_timeout
|
49
|
-
@add_thread = Thread.current
|
50
|
-
give_up_at = Time.now + @job_timeout
|
51
|
-
until Time.now > give_up_at || (@work_queue.size() + @queue.size()) < @max_job_count
|
52
|
-
sleep(@job_timeout)
|
53
|
-
end
|
54
|
-
@add_thread = nil
|
55
|
-
end
|
56
|
-
raise BusyError.new() unless @work_queue.size() < @max_job_count
|
57
|
-
end
|
58
|
-
super
|
59
|
-
end
|
60
|
-
|
61
25
|
private
|
62
26
|
|
63
27
|
# Processes the initialize() options. Subclasses should call super.
|
64
28
|
# @param [Hash] options options to be used for initialization
|
65
29
|
# @option options [Symbol] :method method to call on workers
|
66
|
-
# @option options [Fixnum] :max_job_count maximum number of jobs
|
67
|
-
# that can be queued before backpressure is applied to the caller.
|
68
|
-
# @option options [Float] :job_timeout timeout in seconds to wait
|
69
|
-
# before raising a BusyError if the work queue is too long.
|
70
30
|
def set_options(options)
|
71
31
|
super(options)
|
72
32
|
raise MissingOptionError.new(:method, "for processing jobs") if (@method = options[:method]).nil?
|
73
|
-
@max_job_count = options.fetch(:max_job_count, @max_job_count)
|
74
|
-
@job_timeout = options.fetch(:job_timeout, @job_timeout)
|
75
|
-
end
|
76
|
-
|
77
|
-
# Places a job on the work queue. This method is executed asynchronously.
|
78
|
-
# @param [Object] job work to be processed
|
79
|
-
def add(job)
|
80
|
-
if @workers.empty?
|
81
|
-
@work_queue.insert(0, job)
|
82
|
-
else
|
83
|
-
worker = @workers.pop()
|
84
|
-
worker.ask(@method, job)
|
85
|
-
end
|
86
33
|
end
|
87
34
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
def ready(worker)
|
92
|
-
if @work_queue.empty?
|
93
|
-
@workers.insert(0, worker) unless @workers.include?(worker)
|
94
|
-
else
|
95
|
-
job = @work_queue.pop()
|
96
|
-
@add_thread.wakeup() unless @add_thread.nil?
|
97
|
-
worker.ask(@method, job)
|
98
|
-
end
|
35
|
+
# Asks the worker to invoke the default method on a job.
|
36
|
+
def ask_worker(worker, job)
|
37
|
+
worker.ask(@method, job)
|
99
38
|
end
|
100
39
|
|
101
40
|
end # WorkQueue
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-29 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'An experimental Object-base Parallel Evaluation Environment. '
|
15
15
|
email: peter@ohler.com
|
@@ -19,11 +19,13 @@ extra_rdoc_files:
|
|
19
19
|
- README.md
|
20
20
|
files:
|
21
21
|
- lib/opee/actor.rb
|
22
|
+
- lib/opee/askqueue.rb
|
22
23
|
- lib/opee/collector.rb
|
23
24
|
- lib/opee/env.rb
|
24
25
|
- lib/opee/errors.rb
|
25
26
|
- lib/opee/job.rb
|
26
27
|
- lib/opee/log.rb
|
28
|
+
- lib/opee/queue.rb
|
27
29
|
- lib/opee/version.rb
|
28
30
|
- lib/opee/workqueue.rb
|
29
31
|
- lib/opee.rb
|
@@ -33,7 +35,6 @@ files:
|
|
33
35
|
- test/tc_opee_env.rb
|
34
36
|
- test/tc_opee_log.rb
|
35
37
|
- test/tc_opee_workqueue.rb
|
36
|
-
- test/tests.rb
|
37
38
|
- test/ts_opee.rb
|
38
39
|
- LICENSE
|
39
40
|
- README.md
|
data/test/tests.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby -wW1
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
$: << File.join(File.dirname(__FILE__), "../lib")
|
5
|
-
|
6
|
-
require 'test/unit'
|
7
|
-
require 'opee'
|
8
|
-
require 'relay'
|
9
|
-
|
10
|
-
class Opeet < ::Test::Unit::TestCase
|
11
|
-
|
12
|
-
def test_ask_queue
|
13
|
-
a = ::Relay.new(nil)
|
14
|
-
assert_equal(0, a.queue_count())
|
15
|
-
a.stop()
|
16
|
-
a.ask(:relay, 7)
|
17
|
-
assert_equal(1, a.queue_count())
|
18
|
-
a.start()
|
19
|
-
sleep(0.5)
|
20
|
-
assert_equal(7, a.last_data)
|
21
|
-
a.close()
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_log
|
25
|
-
#::Opee::Env.logger.ask(:severity=, Logger::INFO)
|
26
|
-
::Opee::Env.logger.severity= Logger::INFO
|
27
|
-
::Opee::Env.log(Logger::INFO, "hello")
|
28
|
-
::Opee::Env.each_actor { |a| puts a.to_s }
|
29
|
-
sleep(0.2)
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_wait_close
|
33
|
-
a = ::Relay.new(nil)
|
34
|
-
a.ask(:relay, 7)
|
35
|
-
::Opee::Env.wait_close()
|
36
|
-
assert_equal(7, a.last_data)
|
37
|
-
a.close()
|
38
|
-
end
|
39
|
-
|
40
|
-
end # Opeet
|