mamiya 0.0.1.alpha19 → 0.0.1.alpha20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -0
- data/lib/mamiya/agent.rb +25 -30
- data/lib/mamiya/agent/actions.rb +9 -6
- data/lib/mamiya/agent/handlers/task.rb +13 -0
- data/lib/mamiya/agent/task_queue.rb +151 -0
- data/lib/mamiya/agent/tasks/abstract.rb +61 -0
- data/lib/mamiya/agent/tasks/clean.rb +44 -0
- data/lib/mamiya/agent/tasks/fetch.rb +60 -0
- data/lib/mamiya/agent/tasks/notifyable.rb +30 -0
- data/lib/mamiya/cli/client.rb +1 -1
- data/lib/mamiya/master.rb +4 -9
- data/lib/mamiya/master/agent_monitor_handlers.rb +42 -25
- data/lib/mamiya/master/web.rb +22 -7
- data/lib/mamiya/version.rb +1 -1
- data/mamiya.gemspec +1 -1
- data/spec/agent/actions_spec.rb +2 -8
- data/spec/agent/handlers/task_spec.rb +39 -0
- data/spec/agent/task_queue_spec.rb +246 -0
- data/spec/agent/tasks/abstract_spec.rb +58 -0
- data/spec/agent/tasks/clean_spec.rb +72 -0
- data/spec/agent/tasks/fetch_spec.rb +56 -0
- data/spec/agent/tasks/notifyable_spec.rb +37 -0
- data/spec/agent_spec.rb +33 -54
- data/spec/master/agent_monitor_spec.rb +155 -69
- data/spec/master/web_spec.rb +340 -1
- data/spec/master_spec.rb +0 -21
- metadata +22 -10
- data/lib/mamiya/agent/fetcher.rb +0 -165
- data/lib/mamiya/agent/handlers/fetch.rb +0 -78
- data/spec/agent/fetcher_spec.rb +0 -237
- data/spec/agent/handlers/fetch_spec.rb +0 -127
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'mamiya/agent/tasks/notifyable'
|
2
|
+
require 'mamiya/steps/fetch'
|
3
|
+
require 'mamiya/storages/abstract'
|
4
|
+
|
5
|
+
module Mamiya
|
6
|
+
class Agent
|
7
|
+
module Tasks
|
8
|
+
class Fetch < Notifyable
|
9
|
+
def run
|
10
|
+
logger.info "Fetching #{application}/#{package}"
|
11
|
+
|
12
|
+
take_interval
|
13
|
+
step.run!
|
14
|
+
order_cleaning
|
15
|
+
rescue Mamiya::Storages::Abstract::AlreadyFetched
|
16
|
+
logger.info "It has already fetched; skipping."
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def take_interval
|
22
|
+
fetch_sleep = config[:fetch_sleep]
|
23
|
+
wait = rand(fetch_sleep)
|
24
|
+
|
25
|
+
@logger.info "Sleeping #{wait} sec before starting fetch"
|
26
|
+
rand(wait)
|
27
|
+
end
|
28
|
+
|
29
|
+
def order_cleaning
|
30
|
+
task_queue.enqueue(:clean, {})
|
31
|
+
end
|
32
|
+
|
33
|
+
def application
|
34
|
+
task['app']
|
35
|
+
end
|
36
|
+
|
37
|
+
def package
|
38
|
+
task['pkg']
|
39
|
+
end
|
40
|
+
|
41
|
+
def destination
|
42
|
+
@destination ||= File.join(packages_dir, application)
|
43
|
+
end
|
44
|
+
|
45
|
+
def packages_dir
|
46
|
+
@packages_dir ||= config && config[:packages_dir]
|
47
|
+
end
|
48
|
+
|
49
|
+
def step
|
50
|
+
@step ||= Mamiya::Steps::Fetch.new(
|
51
|
+
application: application,
|
52
|
+
package: package,
|
53
|
+
destination: destination,
|
54
|
+
config: config,
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'mamiya/agent'
|
2
|
+
require 'mamiya/agent/tasks/abstract'
|
3
|
+
|
4
|
+
module Mamiya
|
5
|
+
class Agent
|
6
|
+
module Tasks
|
7
|
+
class Notifyable < Abstract
|
8
|
+
def execute
|
9
|
+
agent.trigger('task', action: 'start',
|
10
|
+
task: task
|
11
|
+
)
|
12
|
+
|
13
|
+
super
|
14
|
+
|
15
|
+
ensure
|
16
|
+
if error
|
17
|
+
agent.trigger('task', action: 'error',
|
18
|
+
error: error.class.name,
|
19
|
+
task: task,
|
20
|
+
)
|
21
|
+
else
|
22
|
+
agent.trigger('task', action: 'finish',
|
23
|
+
task: task,
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/mamiya/cli/client.rb
CHANGED
@@ -10,7 +10,7 @@ require 'thor'
|
|
10
10
|
module Mamiya
|
11
11
|
class CLI < Thor
|
12
12
|
class Client < Thor
|
13
|
-
class_option :master, aliases: '-u', type: :string
|
13
|
+
class_option :master, aliases: '-u', type: :string, default: 'http://localhost:7761/'
|
14
14
|
class_option :application, aliases: %w(-a --app), type: :string
|
15
15
|
|
16
16
|
desc "list-applications", "list applications"
|
data/lib/mamiya/master.rb
CHANGED
@@ -27,7 +27,7 @@ module Mamiya
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def start
|
30
|
-
# Override and stop starting
|
30
|
+
# Override and stop starting task_queue
|
31
31
|
web_start
|
32
32
|
serf_start
|
33
33
|
monitor_start
|
@@ -38,11 +38,6 @@ module Mamiya
|
|
38
38
|
super
|
39
39
|
end
|
40
40
|
|
41
|
-
# XXX: dupe? Mamiya::Agent::Actions#distribute
|
42
|
-
def distribute(application, package)
|
43
|
-
trigger(:fetch, coalesce: false, application: application, package: package)
|
44
|
-
end
|
45
|
-
|
46
41
|
def storage(app)
|
47
42
|
config.storage_class.new(
|
48
43
|
config[:storage].merge(
|
@@ -89,9 +84,9 @@ module Mamiya
|
|
89
84
|
options = config[:web] || {}
|
90
85
|
rack_options = {
|
91
86
|
app: self.web,
|
92
|
-
Port: options[:port].to_i,
|
93
|
-
Host: options[:bind],
|
94
|
-
environment: options[:environment],
|
87
|
+
Port: options[:port] ? options[:port].to_i : 7761,
|
88
|
+
Host: options[:bind] || '0.0.0.0', # TODO: IPv6
|
89
|
+
environment: options[:environment] || :development,
|
95
90
|
server: options[:server],
|
96
91
|
Logger: logger['web']
|
97
92
|
}
|
@@ -2,55 +2,72 @@ require 'mamiya/master'
|
|
2
2
|
|
3
3
|
module Mamiya
|
4
4
|
class Master
|
5
|
+
# XXX: TODO:
|
5
6
|
module AgentMonitorHandlers
|
6
|
-
def
|
7
|
-
|
8
|
-
status['fetcher']['pending'] = payload['pending']
|
7
|
+
def task__start(status, payload, event)
|
8
|
+
task = payload['task']
|
9
9
|
|
10
|
-
status['
|
11
|
-
status['
|
10
|
+
status['queues'] ||= {}
|
11
|
+
status['queues'][task['task']] ||= {'queue' => [], 'working' => nil}
|
12
|
+
|
13
|
+
status['queues'][task['task']]['working'] = task
|
14
|
+
status['queues'][task['task']]['queue'].delete task
|
12
15
|
end
|
13
16
|
|
14
|
-
def
|
15
|
-
|
16
|
-
status['fetcher']['fetching'] = [payload['application'], payload['package']]
|
17
|
+
def task__finalize(status, payload, event)
|
18
|
+
task = payload['task']
|
17
19
|
|
18
|
-
|
20
|
+
status['queues'] ||= {}
|
21
|
+
status['queues'][task['task']] ||= {'queue' => [], 'working' => nil}
|
19
22
|
|
20
|
-
status['
|
21
|
-
|
23
|
+
s = status['queues'][task['task']]
|
24
|
+
if s['working'] == task
|
25
|
+
s['working'] = nil
|
26
|
+
end
|
27
|
+
status['queues'][task['task']]['queue'].delete task
|
22
28
|
end
|
23
29
|
|
24
|
-
def
|
25
|
-
|
30
|
+
def task__finish(status, payload, event)
|
31
|
+
task = payload['task']
|
32
|
+
logger.error "#{status['name']} finished task #{task['task']}: #{payload['error']}"
|
26
33
|
|
27
|
-
|
34
|
+
task__finalize(status, payload, event)
|
28
35
|
|
29
|
-
|
30
|
-
|
36
|
+
method_name = "task___#{task['task']}__finish"
|
37
|
+
if self.respond_to?(method_name)
|
38
|
+
__send__ method_name, status, task
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
34
|
-
def
|
35
|
-
|
42
|
+
def task__error(status, payload, event)
|
43
|
+
task = payload['task']
|
44
|
+
logger.error "#{status['name']} failed task #{task['task']}: #{payload['error']}"
|
36
45
|
|
37
|
-
|
46
|
+
task__finalize(status, payload, event)
|
38
47
|
|
39
|
-
|
40
|
-
|
48
|
+
method_name = "task___#{task['task']}__error"
|
49
|
+
if self.respond_to?(method_name)
|
50
|
+
__send__ method_name, status, task, error
|
41
51
|
end
|
52
|
+
end
|
53
|
+
|
42
54
|
|
55
|
+
|
56
|
+
# XXX: move task finish handlers into tasks/
|
57
|
+
def task___fetch__finish(status, task)
|
43
58
|
status['packages'] ||= {}
|
44
|
-
status['packages'][
|
45
|
-
|
59
|
+
status['packages'][task['app']] ||= []
|
60
|
+
|
61
|
+
unless status['packages'][task['app']].include?(task['pkg'])
|
62
|
+
status['packages'][task['app']] << task['pkg']
|
63
|
+
end
|
46
64
|
end
|
47
65
|
|
48
|
-
def
|
66
|
+
def pkg__remove(status, payload, event)
|
49
67
|
status['packages'] ||= {}
|
50
68
|
packages = status['packages'][payload['application']]
|
51
69
|
packages.delete(payload['package']) if packages
|
52
70
|
end
|
53
|
-
|
54
71
|
end
|
55
72
|
end
|
56
73
|
end
|
data/lib/mamiya/master/web.rb
CHANGED
@@ -21,7 +21,8 @@ module Mamiya
|
|
21
21
|
end
|
22
22
|
|
23
23
|
get '/' do
|
24
|
-
|
24
|
+
content_type 'text/plain'
|
25
|
+
"mamiya v#{Mamiya::VERSION}\n"
|
25
26
|
end
|
26
27
|
|
27
28
|
get '/packages/:application' do
|
@@ -88,15 +89,29 @@ module Mamiya
|
|
88
89
|
|
89
90
|
statuses.each do |name, status|
|
90
91
|
next if status["master"]
|
91
|
-
|
92
|
-
|
92
|
+
queue = status["queues"] && status["queues"]["fetch"]
|
93
|
+
packages = status["packages"] && status["packages"][params[:application]]
|
94
|
+
|
95
|
+
task_matcher = -> (task) do
|
96
|
+
task["task"] == "fetch" &&
|
97
|
+
task["app"] == params[:application] &&
|
98
|
+
task["pkg"] == params[:package]
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
case
|
103
|
+
when packages && packages.include?(params[:package])
|
93
104
|
|
94
105
|
result[:distributed] << name
|
95
|
-
|
106
|
+
|
107
|
+
when queue && queue["working"] && task_matcher.call(queue['working'])
|
108
|
+
|
96
109
|
result[:fetching] << name
|
97
|
-
|
98
|
-
|
110
|
+
|
111
|
+
when queue['queue'].any?(&task_matcher)
|
112
|
+
|
99
113
|
result[:queued] << name
|
114
|
+
|
100
115
|
else
|
101
116
|
result[:not_distributed] << name
|
102
117
|
end
|
@@ -113,7 +128,7 @@ module Mamiya
|
|
113
128
|
when 0 < result[:queued_count] || 0 < result[:fetching_count]
|
114
129
|
status = :distributing
|
115
130
|
when 0 < result[:distributed_count] && result[:distributed_count] < total
|
116
|
-
status = :
|
131
|
+
status = :partially_distributed
|
117
132
|
when result[:distributed_count] == total
|
118
133
|
status = :distributed
|
119
134
|
else
|
data/lib/mamiya/version.rb
CHANGED
data/mamiya.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency "thor", ">= 0.18.1"
|
22
|
-
spec.add_runtime_dependency "aws-sdk-core", "2.0.0.
|
22
|
+
spec.add_runtime_dependency "aws-sdk-core", "2.0.0.rc15"
|
23
23
|
spec.add_runtime_dependency "term-ansicolor", ">= 1.3.0"
|
24
24
|
unless ENV["MAMIYA_VILLEIN_PATH"]
|
25
25
|
spec.add_runtime_dependency "villein", ">= 0.3.2"
|
data/spec/agent/actions_spec.rb
CHANGED
@@ -10,7 +10,6 @@ require_relative '../support/dummy_serf.rb'
|
|
10
10
|
|
11
11
|
describe Mamiya::Agent::Actions do
|
12
12
|
let(:serf) { DummySerf.new }
|
13
|
-
let(:fetcher) { double('fetcher', start!: nil) }
|
14
13
|
|
15
14
|
let(:config) do
|
16
15
|
{serf: {agent: {rpc_addr: '127.0.0.1:17373', bind: '127.0.0.1:17946'}}}
|
@@ -18,7 +17,6 @@ describe Mamiya::Agent::Actions do
|
|
18
17
|
|
19
18
|
before do
|
20
19
|
allow(Villein::Agent).to receive(:new).and_return(serf)
|
21
|
-
allow(Mamiya::Agent::Fetcher).to receive(:new).and_return(fetcher)
|
22
20
|
end
|
23
21
|
|
24
22
|
subject(:agent) { Mamiya::Agent.new(config) }
|
@@ -26,13 +24,9 @@ describe Mamiya::Agent::Actions do
|
|
26
24
|
|
27
25
|
describe "#distribute" do
|
28
26
|
it "sends fetch request" do
|
29
|
-
expect(
|
30
|
-
'mamiya:fetch',
|
31
|
-
{application: 'app', package: 'pkg'}.to_json,
|
32
|
-
coalesce: false
|
33
|
-
)
|
27
|
+
expect(agent).to receive(:trigger).with('task', task: 'fetch', app: 'myapp', pkg: 'mypkg', coalesce: false)
|
34
28
|
|
35
|
-
agent.distribute('
|
29
|
+
agent.distribute('myapp', 'mypkg')
|
36
30
|
end
|
37
31
|
end
|
38
32
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'villein/event'
|
5
|
+
|
6
|
+
require 'mamiya/agent/handlers/task'
|
7
|
+
|
8
|
+
describe Mamiya::Agent::Handlers::Task do
|
9
|
+
let(:event) do
|
10
|
+
Villein::Event.new(
|
11
|
+
{
|
12
|
+
'SERF_EVENT' => 'user',
|
13
|
+
'SERF_USER_EVENT' => 'mamiya:task',
|
14
|
+
},
|
15
|
+
payload: {
|
16
|
+
task: 'fetch',
|
17
|
+
application: 'app',
|
18
|
+
package: 'package',
|
19
|
+
}.to_json,
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:task_queue) { double('task_queue', enqueue: nil) }
|
24
|
+
|
25
|
+
let(:agent) do
|
26
|
+
double('agent', task_queue: task_queue)
|
27
|
+
end
|
28
|
+
|
29
|
+
subject(:handler) { described_class.new(agent, event) }
|
30
|
+
|
31
|
+
before do
|
32
|
+
end
|
33
|
+
|
34
|
+
it "enqueue a request" do
|
35
|
+
expect(task_queue).to receive(:enqueue).with(:fetch, 'task' => 'fetch', 'application' => 'app', 'package' => 'package')
|
36
|
+
|
37
|
+
handler.run!
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'thread'
|
3
|
+
require 'mamiya/agent/tasks/abstract'
|
4
|
+
require 'mamiya/agent/task_queue'
|
5
|
+
|
6
|
+
describe Mamiya::Agent::TaskQueue do
|
7
|
+
let(:agent) do
|
8
|
+
double('agent')
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:task_class_root) do
|
12
|
+
Class.new(Mamiya::Agent::Tasks::Abstract) do
|
13
|
+
def self.runs
|
14
|
+
@runs ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.locks
|
18
|
+
@locks ||= {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.locks_lock
|
22
|
+
@locks_lock ||= Mutex.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
self.class.runs << task.dup
|
27
|
+
if task['wait']
|
28
|
+
begin
|
29
|
+
queue = Queue.new
|
30
|
+
self.class.locks_lock.synchronize do
|
31
|
+
self.class.locks[self.task] = queue
|
32
|
+
end
|
33
|
+
queue.pop
|
34
|
+
ensure
|
35
|
+
self.class.locks_lock.synchronize do
|
36
|
+
self.class.locks.delete self.task
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
let(:task_class_a) do
|
46
|
+
Class.new(task_class_root) do
|
47
|
+
def self.identifier
|
48
|
+
'a'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
let(:task_class_b) do
|
54
|
+
Class.new(task_class_root) do
|
55
|
+
def self.identifier
|
56
|
+
'b'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
subject(:queue) do
|
62
|
+
described_class.new(agent, task_classes: [task_class_a, task_class_b])
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "lifecycle (#start!, #stop!)" do
|
66
|
+
it "can start and stop" do
|
67
|
+
expect(queue).not_to be_running
|
68
|
+
expect(queue.worker_threads).to be_nil
|
69
|
+
|
70
|
+
queue.start!
|
71
|
+
|
72
|
+
expect(queue).to be_running
|
73
|
+
|
74
|
+
expect(queue.worker_threads).to be_a_kind_of(Hash)
|
75
|
+
expect(queue.worker_threads.values.all? { |v| v.kind_of?(Thread) }).to be_true
|
76
|
+
expect(queue.worker_threads.values.all? { |v| v.alive? }).to be_true
|
77
|
+
threads = queue.worker_threads.dup
|
78
|
+
|
79
|
+
queue.stop!
|
80
|
+
|
81
|
+
expect(queue).not_to be_running
|
82
|
+
expect(queue.worker_threads).to be_nil
|
83
|
+
expect(threads.each_value.all? { |v| !v.alive? }).to be_true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can stop gracefully"
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "work loop (#enqueue, #running?, #working, #status)" do
|
90
|
+
after do
|
91
|
+
queue.stop! if queue.running?
|
92
|
+
end
|
93
|
+
|
94
|
+
it "run enqueued task" do
|
95
|
+
queue.start!
|
96
|
+
|
97
|
+
queue.enqueue(:a, 'foo' => '1')
|
98
|
+
queue.enqueue(:a, 'foo' => '2')
|
99
|
+
100.times { break if task_class_a.runs.size == 2; sleep 0.01 }
|
100
|
+
|
101
|
+
expect(task_class_a.runs.size).to eq 2
|
102
|
+
expect(task_class_a.runs[0]['foo']).to eq '1'
|
103
|
+
expect(task_class_a.runs[1]['foo']).to eq '2'
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#working?" do
|
107
|
+
it "returns true if there're any working tasks" do
|
108
|
+
queue.start!
|
109
|
+
|
110
|
+
expect(queue).not_to be_working
|
111
|
+
|
112
|
+
queue.enqueue(:a, 'wait' => true, 'id' => 1)
|
113
|
+
100.times { break unless task_class_a.locks.empty?; sleep 0.01 }
|
114
|
+
expect(task_class_a.locks).not_to be_empty
|
115
|
+
expect(queue).to be_working
|
116
|
+
|
117
|
+
task_class_a.locks.values.last << true
|
118
|
+
|
119
|
+
100.times { break unless queue.working?; sleep 0.01 }
|
120
|
+
expect(queue).not_to be_working
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
describe "#status" do
|
126
|
+
it "shows status" do
|
127
|
+
queue.start!
|
128
|
+
|
129
|
+
expect(queue.status[:a][:working]).to be_nil
|
130
|
+
expect(queue.status[:a][:queue]).to be_a_kind_of(Array)
|
131
|
+
expect(queue.status[:a][:queue]).to be_empty
|
132
|
+
|
133
|
+
queue.enqueue(:a, 'wait' => true, 'id' => 1)
|
134
|
+
|
135
|
+
100.times { break unless task_class_a.locks.empty?; sleep 0.01 }
|
136
|
+
expect(task_class_a.locks).not_to be_empty
|
137
|
+
expect(queue.status[:a][:working]).to eq('wait' => true, 'id' => 1)
|
138
|
+
|
139
|
+
queue.enqueue(:a, 'id' => 2)
|
140
|
+
100.times { break unless queue.status[:a][:queue].empty?; sleep 0.01 }
|
141
|
+
expect(queue.status[:a][:queue].size).to eq 1
|
142
|
+
expect(queue.status[:a][:queue].first).to eq('id' => 2)
|
143
|
+
|
144
|
+
task_class_a.locks.values.last << true
|
145
|
+
|
146
|
+
100.times { break unless queue.status[:a][:working]; sleep 0.01 }
|
147
|
+
expect(queue.status[:a][:working]).to be_nil
|
148
|
+
expect(queue.status[:a][:queue]).to be_empty
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "with multiple task classes" do
|
153
|
+
it "run enqueued task" do
|
154
|
+
queue.start!
|
155
|
+
|
156
|
+
queue.enqueue(:a, 'foo' => '1')
|
157
|
+
queue.enqueue(:b, 'foo' => '2')
|
158
|
+
100.times { break if task_class_a.runs.size == 1 && task_class_b.runs.size == 1; sleep 0.01 }
|
159
|
+
|
160
|
+
expect(task_class_a.runs.size).to eq 1
|
161
|
+
expect(task_class_b.runs.size).to eq 1
|
162
|
+
expect(task_class_a.runs[0]['foo']).to eq '1'
|
163
|
+
expect(task_class_b.runs[0]['foo']).to eq '2'
|
164
|
+
end
|
165
|
+
|
166
|
+
it "run enqueued task parallel" do
|
167
|
+
queue.start!
|
168
|
+
|
169
|
+
queue.enqueue(:a, 'foo' => '1', 'wait' => true)
|
170
|
+
queue.enqueue(:b, 'foo' => '2', 'wait' => true)
|
171
|
+
100.times { break if task_class_a.locks.size == 1 && task_class_b.locks.size == 1; sleep 0.01 }
|
172
|
+
|
173
|
+
expect(task_class_a.locks.size).to eq 1
|
174
|
+
expect(task_class_b.locks.size).to eq 1
|
175
|
+
task_class_a.locks.each_value.first << true
|
176
|
+
task_class_b.locks.each_value.first << true
|
177
|
+
|
178
|
+
expect(task_class_a.runs.size).to eq 1
|
179
|
+
expect(task_class_b.runs.size).to eq 1
|
180
|
+
expect(task_class_a.runs[0]['foo']).to eq '1'
|
181
|
+
expect(task_class_b.runs[0]['foo']).to eq '2'
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "#status" do
|
185
|
+
it "shows status for each task class" do
|
186
|
+
queue.start!
|
187
|
+
|
188
|
+
expect(queue.status[:a][:working]).to be_nil
|
189
|
+
expect(queue.status[:a][:queue]).to be_a_kind_of(Array)
|
190
|
+
expect(queue.status[:a][:queue]).to be_empty
|
191
|
+
|
192
|
+
expect(queue.status[:b][:working]).to be_nil
|
193
|
+
expect(queue.status[:b][:queue]).to be_a_kind_of(Array)
|
194
|
+
expect(queue.status[:b][:queue]).to be_empty
|
195
|
+
|
196
|
+
queue.enqueue(:a, 'wait' => true, 'id' => 1)
|
197
|
+
queue.enqueue(:b, 'wait' => true, 'id' => 2)
|
198
|
+
|
199
|
+
100.times { break if !task_class_a.locks.empty? && !task_class_a.locks.empty?; sleep 0.01 }
|
200
|
+
expect(task_class_a.locks).not_to be_empty
|
201
|
+
expect(task_class_b.locks).not_to be_empty
|
202
|
+
|
203
|
+
expect(queue.status[:a][:working]).to eq('wait' => true, 'id' => 1)
|
204
|
+
expect(queue.status[:b][:working]).to eq('wait' => true, 'id' => 2)
|
205
|
+
|
206
|
+
queue.enqueue(:a, 'id' => 3)
|
207
|
+
queue.enqueue(:b, 'id' => 4)
|
208
|
+
100.times { break if !queue.status[:a][:queue].empty? && !queue.status[:b][:queue].empty?; sleep 0.01 }
|
209
|
+
expect(queue.status[:a][:queue].size).to eq 1
|
210
|
+
expect(queue.status[:a][:queue].first).to eq('id' => 3)
|
211
|
+
expect(queue.status[:b][:queue].size).to eq 1
|
212
|
+
expect(queue.status[:b][:queue].first).to eq('id' => 4)
|
213
|
+
|
214
|
+
task_class_a.locks.values.last << true
|
215
|
+
task_class_b.locks.values.last << true
|
216
|
+
|
217
|
+
100.times { break if !queue.status[:a][:working] && !queue.status[:b][:working]; sleep 0.01 }
|
218
|
+
expect(queue.status[:a][:working]).to be_nil
|
219
|
+
expect(queue.status[:a][:queue]).to be_empty
|
220
|
+
expect(queue.status[:b][:working]).to be_nil
|
221
|
+
expect(queue.status[:b][:queue]).to be_empty
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "#working?" do
|
227
|
+
it "returns true if there're any working tasks" do
|
228
|
+
queue.start!
|
229
|
+
|
230
|
+
expect(queue).not_to be_working
|
231
|
+
|
232
|
+
queue.enqueue(:a, 'wait' => true, 'id' => 1)
|
233
|
+
100.times { break unless task_class_a.locks.empty?; sleep 0.01 }
|
234
|
+
expect(task_class_a.locks).not_to be_empty
|
235
|
+
expect(queue).to be_working
|
236
|
+
|
237
|
+
task_class_a.locks.values.last << true
|
238
|
+
|
239
|
+
100.times { break unless queue.working?; sleep 0.01 }
|
240
|
+
expect(queue).not_to be_working
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|