bumbleworks 0.0.90 → 0.0.91
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/lib/bumbleworks/version.rb +1 -1
- data/lib/bumbleworks/worker.rb +47 -14
- data/lib/bumbleworks/worker/info.rb +104 -26
- data/lib/bumbleworks/worker/proxy.rb +17 -2
- data/spec/lib/bumbleworks/worker/info_spec.rb +190 -23
- data/spec/lib/bumbleworks/worker/proxy_spec.rb +28 -3
- data/spec/lib/bumbleworks/worker_spec.rb +35 -17
- data/spec/support/matchers/delegation_matcher.rb +9 -0
- data/spec/support/matchers/fetch_matcher.rb +9 -0
- data/spec/support/{shared_examples.rb → shared_examples/comparable.rb} +0 -17
- data/spec/support/shared_examples/entity_holder.rb +16 -0
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a41e2e146849e9de9752fcc88353008da72e6c94
|
4
|
+
data.tar.gz: 776a60a147c9cbd1512cae7d81519667ec514c2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f1d34125e457ae2b08b599d80cddd4e2f51b7ae332636d14c52cfb0fa2dd8f40e92ccc9336c30356d43bf17593338c5018bb5e1cc0d5a0e90ce0a5fd7d8a030
|
7
|
+
data.tar.gz: 01636c8cf9af7e4b5f452282f663962ef16afe8520ccb469a5f1deb8730bbcd76f810acb39aae6eaf13e3e436e41ea14f017910a479994c11414abe0c30c94ca
|
data/.travis.yml
ADDED
data/lib/bumbleworks/version.rb
CHANGED
data/lib/bumbleworks/worker.rb
CHANGED
@@ -8,12 +8,13 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
8
8
|
|
9
9
|
class << self
|
10
10
|
def info
|
11
|
-
Bumbleworks
|
11
|
+
Bumbleworks::Worker::Info || {}
|
12
12
|
end
|
13
13
|
|
14
14
|
def shutdown_all(options = {})
|
15
15
|
# First, send all running workers a message to stop
|
16
16
|
change_worker_state('stopped', options)
|
17
|
+
ensure
|
17
18
|
# Now ensure that future started workers will be started
|
18
19
|
# in "running" mode instead of automatically stopped
|
19
20
|
change_worker_state('running', options)
|
@@ -27,10 +28,10 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
27
28
|
change_worker_state('running', options)
|
28
29
|
end
|
29
30
|
|
30
|
-
def
|
31
|
+
def active_worker_states
|
31
32
|
info.inject({}) { |hsh, info|
|
32
|
-
id, state = info
|
33
|
-
|
33
|
+
id, state = info.id, info.state
|
34
|
+
unless info.state.nil? || info.in_stopped_state?
|
34
35
|
hsh[id] = state
|
35
36
|
end
|
36
37
|
hsh
|
@@ -41,21 +42,20 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
41
42
|
with_worker_state_enabled do
|
42
43
|
Bumbleworks.dashboard.worker_state = new_state
|
43
44
|
Bumbleworks::Support.wait_until(options) do
|
44
|
-
|
45
|
+
active_worker_states.values.all? { |state| state == new_state }
|
45
46
|
end
|
46
47
|
end
|
47
48
|
return true
|
48
49
|
rescue Bumbleworks::Support::WaitTimeout
|
49
|
-
raise WorkerStateNotChanged, "Worker states: #{
|
50
|
+
raise WorkerStateNotChanged, "Worker states: #{active_worker_states.inspect}"
|
50
51
|
end
|
51
52
|
|
52
53
|
def refresh_worker_info(options = {})
|
53
54
|
with_worker_state_enabled do
|
54
|
-
|
55
|
-
|
56
|
-
worker_info
|
57
|
-
|
58
|
-
}
|
55
|
+
info.each do |worker_info|
|
56
|
+
if !worker_info.in_stopped_state? && worker_info.stalling?
|
57
|
+
worker_info.record_new_state("stalled")
|
58
|
+
end
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -65,6 +65,22 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
65
65
|
yield
|
66
66
|
Bumbleworks.dashboard.context['worker_state_enabled'] = false
|
67
67
|
end
|
68
|
+
|
69
|
+
def control_document
|
70
|
+
doc = Bumbleworks.dashboard.storage.get('variables', 'worker_control') || {}
|
71
|
+
doc['type'] = 'variables'
|
72
|
+
doc['_id'] = 'worker_control'
|
73
|
+
doc['workers'] ||= {}
|
74
|
+
doc
|
75
|
+
end
|
76
|
+
|
77
|
+
def info_document
|
78
|
+
doc = Bumbleworks.dashboard.storage.get('variables', 'workers') || {}
|
79
|
+
doc['type'] = 'variables'
|
80
|
+
doc['_id'] = 'workers'
|
81
|
+
doc['workers'] ||= {}
|
82
|
+
doc
|
83
|
+
end
|
68
84
|
end
|
69
85
|
|
70
86
|
def initialize(*args, &block)
|
@@ -83,6 +99,10 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
83
99
|
end
|
84
100
|
end
|
85
101
|
|
102
|
+
def class_name
|
103
|
+
self.class.to_s
|
104
|
+
end
|
105
|
+
|
86
106
|
def save_info
|
87
107
|
@info.save if @info
|
88
108
|
end
|
@@ -92,10 +112,23 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
92
112
|
save_info
|
93
113
|
end
|
94
114
|
|
115
|
+
def worker_control_variable
|
116
|
+
self.class.control_document["workers"][id]
|
117
|
+
end
|
118
|
+
|
119
|
+
def desired_state
|
120
|
+
control_hash = worker_control_variable ||
|
121
|
+
@storage.get("variables", "worker") ||
|
122
|
+
{ "state" => "running" }
|
123
|
+
control_hash["state"]
|
124
|
+
end
|
125
|
+
|
95
126
|
def determine_state
|
96
|
-
|
97
|
-
|
98
|
-
|
127
|
+
@state_mutex.synchronize do
|
128
|
+
if @state != "stopped" && @context["worker_state_enabled"]
|
129
|
+
@state = desired_state
|
130
|
+
save_info
|
131
|
+
end
|
99
132
|
end
|
100
133
|
end
|
101
134
|
|
@@ -3,18 +3,27 @@ require_relative "proxy"
|
|
3
3
|
class Bumbleworks::Worker < Ruote::Worker
|
4
4
|
class Info < Ruote::Worker::Info
|
5
5
|
attr_reader :worker
|
6
|
+
extend Forwardable
|
7
|
+
extend Enumerable
|
8
|
+
|
9
|
+
def_delegators :worker,
|
10
|
+
:id, :pid, :name, :state, :ip, :hostname, :system, :launched_at
|
6
11
|
|
7
12
|
class << self
|
8
13
|
def raw_hash
|
9
14
|
Bumbleworks.dashboard.worker_info || {}
|
10
15
|
end
|
11
16
|
|
12
|
-
def
|
13
|
-
raw_hash.
|
14
|
-
from_hash(v
|
17
|
+
def each
|
18
|
+
raw_hash.each { |k, v|
|
19
|
+
yield from_hash(v)
|
15
20
|
}
|
16
21
|
end
|
17
22
|
|
23
|
+
def all
|
24
|
+
to_a
|
25
|
+
end
|
26
|
+
|
18
27
|
def where(options)
|
19
28
|
filter_proc = proc { |worker|
|
20
29
|
options.all? { |k, v|
|
@@ -26,11 +35,11 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
26
35
|
|
27
36
|
def filter
|
28
37
|
return [] unless block_given?
|
29
|
-
|
38
|
+
select { |info| yield info.worker }
|
30
39
|
end
|
31
40
|
|
32
41
|
def [](worker_id)
|
33
|
-
from_hash(raw_hash[worker_id]
|
42
|
+
from_hash(raw_hash[worker_id])
|
34
43
|
end
|
35
44
|
|
36
45
|
def from_hash(hash)
|
@@ -61,6 +70,13 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
73
|
+
def initialize(worker)
|
74
|
+
@worker = worker
|
75
|
+
@last_save = Time.now - 2 * 60
|
76
|
+
|
77
|
+
@msgs = [] unless worker.is_a?(Bumbleworks::Worker::Proxy)
|
78
|
+
end
|
79
|
+
|
64
80
|
def ==(other)
|
65
81
|
other.is_a?(Bumbleworks::Worker::Info) &&
|
66
82
|
other.worker == worker
|
@@ -70,6 +86,31 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
70
86
|
self.class.raw_hash[worker.id]
|
71
87
|
end
|
72
88
|
|
89
|
+
def reload
|
90
|
+
@worker = Bumbleworks::Worker::Proxy.new(raw_hash)
|
91
|
+
end
|
92
|
+
|
93
|
+
def record_new_state(state)
|
94
|
+
worker.state = state
|
95
|
+
save
|
96
|
+
end
|
97
|
+
|
98
|
+
def worker_class_name
|
99
|
+
worker.class_name
|
100
|
+
end
|
101
|
+
|
102
|
+
def uptime
|
103
|
+
if in_stopped_state? && worker.respond_to?(:uptime)
|
104
|
+
worker.uptime
|
105
|
+
else
|
106
|
+
Time.now - worker.launched_at
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def in_stopped_state?
|
111
|
+
worker.state.nil? || ["stopped", "stalled"].include?(worker.state)
|
112
|
+
end
|
113
|
+
|
73
114
|
def updated_at
|
74
115
|
Time.parse(raw_hash['put_at'])
|
75
116
|
end
|
@@ -104,39 +145,76 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
104
145
|
@worker.storage || Bumbleworks.dashboard.storage
|
105
146
|
end
|
106
147
|
|
107
|
-
def
|
108
|
-
|
109
|
-
|
148
|
+
def shutdown(options = {})
|
149
|
+
send_command("stopped", options)
|
150
|
+
end
|
110
151
|
|
111
|
-
|
152
|
+
def pause(options = {})
|
153
|
+
send_command("paused", options)
|
154
|
+
end
|
155
|
+
|
156
|
+
def unpause(options = {})
|
157
|
+
send_command("running", options)
|
112
158
|
end
|
113
159
|
|
114
|
-
|
115
|
-
|
160
|
+
alias_method :run, :unpause
|
161
|
+
|
162
|
+
def send_command(command, options = {})
|
163
|
+
save_control_message(command)
|
164
|
+
Bumbleworks::Worker.with_worker_state_enabled do
|
165
|
+
Bumbleworks::Support.wait_until(options) do
|
166
|
+
raw_hash["state"] == command
|
167
|
+
end
|
168
|
+
end
|
169
|
+
reload
|
170
|
+
end
|
171
|
+
|
172
|
+
def save_control_message(message)
|
173
|
+
doc = Bumbleworks::Worker.control_document
|
174
|
+
doc["workers"][id] ||= {}
|
175
|
+
doc["workers"][id]["state"] = message
|
176
|
+
storage.put(doc)
|
177
|
+
end
|
178
|
+
|
179
|
+
def processed_last_minute
|
180
|
+
raw_hash["processed_last_minute"]
|
181
|
+
end
|
182
|
+
|
183
|
+
def wait_time_last_minute
|
184
|
+
raw_hash["wait_time_last_minute"]
|
185
|
+
end
|
186
|
+
|
187
|
+
def processed_last_hour
|
188
|
+
raw_hash["processed_last_hour"]
|
189
|
+
end
|
190
|
+
|
191
|
+
def wait_time_last_hour
|
192
|
+
raw_hash["wait_time_last_hour"]
|
193
|
+
end
|
116
194
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
195
|
+
def constant_worker_info_hash
|
196
|
+
{
|
197
|
+
"id" => @worker.id,
|
198
|
+
"class" => @worker.class_name,
|
199
|
+
"name" => @worker.name,
|
200
|
+
"ip" => @worker.ip,
|
201
|
+
"hostname" => @worker.hostname,
|
202
|
+
"pid" => @worker.pid,
|
203
|
+
"system" => @worker.system,
|
204
|
+
"launched_at" => @worker.launched_at,
|
205
|
+
"state" => @worker.state
|
206
|
+
}
|
121
207
|
end
|
122
208
|
|
123
209
|
def save
|
124
|
-
doc =
|
210
|
+
doc = Bumbleworks::Worker.info_document
|
125
211
|
|
126
212
|
worker_info_hash = doc['workers'][@worker.id] || {}
|
127
213
|
|
214
|
+
worker_info_hash.merge!(constant_worker_info_hash)
|
128
215
|
worker_info_hash.merge!({
|
129
|
-
'worker_id' => @worker.id,
|
130
|
-
'class' => @worker.class.to_s,
|
131
|
-
'name' => @worker.name,
|
132
|
-
'ip' => @worker.ip,
|
133
|
-
'hostname' => @worker.hostname,
|
134
|
-
'pid' => @worker.pid,
|
135
|
-
'system' => @worker.system,
|
136
216
|
'put_at' => Ruote.now_to_utc_s,
|
137
|
-
'uptime' =>
|
138
|
-
'launched_at' => @worker.launched_at,
|
139
|
-
'state' => @worker.state
|
217
|
+
'uptime' => uptime,
|
140
218
|
})
|
141
219
|
|
142
220
|
if defined?(@msgs)
|
@@ -1,11 +1,12 @@
|
|
1
1
|
class Bumbleworks::Worker < Ruote::Worker
|
2
2
|
class Proxy
|
3
3
|
ProxiedAttributes = [
|
4
|
-
:id, :pid, :ip, :hostname, :system, :launched_at, :state, :name, :class
|
4
|
+
:id, :pid, :ip, :hostname, :system, :launched_at, :state, :name, :class, :uptime
|
5
5
|
]
|
6
6
|
|
7
7
|
attr_reader *(ProxiedAttributes - [:launched_at])
|
8
8
|
attr_reader :raw_hash
|
9
|
+
attr_writer :state
|
9
10
|
|
10
11
|
def initialize(attributes)
|
11
12
|
@raw_hash = attributes
|
@@ -14,8 +15,22 @@ class Bumbleworks::Worker < Ruote::Worker
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
# Allow storage to revert to the default for this Bumbleworks
|
19
|
+
# instance.
|
20
|
+
def storage
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def class_name
|
25
|
+
@class.to_s
|
26
|
+
end
|
27
|
+
|
17
28
|
def launched_at
|
18
|
-
|
29
|
+
if @launched_at.is_a?(String)
|
30
|
+
Time.parse(@launched_at)
|
31
|
+
else
|
32
|
+
@launched_at
|
33
|
+
end
|
19
34
|
end
|
20
35
|
|
21
36
|
def ==(other)
|
@@ -2,19 +2,51 @@ describe Bumbleworks::Worker::Info do
|
|
2
2
|
let(:context) { Bumbleworks.dashboard.context }
|
3
3
|
let(:proxy) {
|
4
4
|
Bumbleworks::Worker::Proxy.new(
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
"class" => "f_class",
|
6
|
+
"pid" => "f_pid",
|
7
|
+
"name" => "f_name",
|
8
|
+
"id" => "f_id",
|
9
|
+
"state" => "f_state",
|
10
|
+
"ip" => "f_ip",
|
11
|
+
"hostname" => "f_hostname",
|
12
|
+
"system" => "f_system",
|
13
|
+
"uptime" => "f_uptime",
|
14
|
+
"launched_at" => "2010-10-10 10:10:10"
|
14
15
|
)
|
15
16
|
}
|
16
17
|
subject { described_class.new(proxy) }
|
17
18
|
|
19
|
+
|
20
|
+
describe "delegation to hash" do
|
21
|
+
let(:raw_hash) {
|
22
|
+
{
|
23
|
+
"processed_last_minute" => 20,
|
24
|
+
"wait_time_last_minute" => 300.5,
|
25
|
+
"processed_last_hour" => 540,
|
26
|
+
"wait_time_last_hour" => 15.6
|
27
|
+
}
|
28
|
+
}
|
29
|
+
before(:each) do
|
30
|
+
allow(subject).to receive(:raw_hash).and_return(raw_hash)
|
31
|
+
end
|
32
|
+
|
33
|
+
it { is_expected.to fetch(:processed_last_minute).from(raw_hash) }
|
34
|
+
it { is_expected.to fetch(:wait_time_last_minute).from(raw_hash) }
|
35
|
+
it { is_expected.to fetch(:processed_last_hour).from(raw_hash) }
|
36
|
+
it { is_expected.to fetch(:wait_time_last_hour).from(raw_hash) }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "delegation to worker/proxy" do
|
40
|
+
it { is_expected.to delegate(:id).to(proxy) }
|
41
|
+
it { is_expected.to delegate(:pid).to(proxy) }
|
42
|
+
it { is_expected.to delegate(:name).to(proxy) }
|
43
|
+
it { is_expected.to delegate(:state).to(proxy) }
|
44
|
+
it { is_expected.to delegate(:ip).to(proxy) }
|
45
|
+
it { is_expected.to delegate(:hostname).to(proxy) }
|
46
|
+
it { is_expected.to delegate(:system).to(proxy) }
|
47
|
+
it { is_expected.to delegate(:launched_at).to(proxy) }
|
48
|
+
end
|
49
|
+
|
18
50
|
describe '.raw_hash' do
|
19
51
|
it 'returns Bumbleworks.dashboard.worker_info' do
|
20
52
|
allow(Bumbleworks.dashboard).to receive(:worker_info).and_return(:bontron)
|
@@ -30,15 +62,16 @@ describe Bumbleworks::Worker::Info do
|
|
30
62
|
describe '.from_hash' do
|
31
63
|
it 'returns an info object using a proxy worker with given attributes' do
|
32
64
|
hash = {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
65
|
+
"class" => "f_class",
|
66
|
+
"pid" => "f_pid",
|
67
|
+
"name" => "f_name",
|
68
|
+
"id" => "f_id",
|
69
|
+
"state" => "f_state",
|
70
|
+
"ip" => "f_ip",
|
71
|
+
"hostname" => "f_hostname",
|
72
|
+
"system" => "f_system",
|
73
|
+
"uptime" => "f_uptime",
|
74
|
+
"launched_at" => "2010-10-10 10:10:10"
|
42
75
|
}
|
43
76
|
allow(described_class).to receive(:new).
|
44
77
|
with(proxy).
|
@@ -60,7 +93,7 @@ describe Bumbleworks::Worker::Info do
|
|
60
93
|
describe '.[]' do
|
61
94
|
it 'calls from_hash with raw data for given worker id' do
|
62
95
|
allow(described_class).to receive(:from_hash).
|
63
|
-
with({ 'foo' => 1
|
96
|
+
with({ 'foo' => 1 }).and_return(:foo_info)
|
64
97
|
expect(described_class['f_id']).to eq(:foo_info)
|
65
98
|
end
|
66
99
|
end
|
@@ -68,9 +101,9 @@ describe Bumbleworks::Worker::Info do
|
|
68
101
|
describe '.all' do
|
69
102
|
it 'converts raw hash into info instances' do
|
70
103
|
allow(described_class).to receive(:from_hash).
|
71
|
-
with({ 'foo' => 1
|
104
|
+
with({ 'foo' => 1 }).and_return(:foo_info)
|
72
105
|
allow(described_class).to receive(:from_hash).
|
73
|
-
with({ 'bar' => 1
|
106
|
+
with({ 'bar' => 1 }).and_return(:bar_info)
|
74
107
|
expect(described_class.all).to match_array([:foo_info, :bar_info])
|
75
108
|
end
|
76
109
|
end
|
@@ -128,6 +161,26 @@ describe Bumbleworks::Worker::Info do
|
|
128
161
|
end
|
129
162
|
end
|
130
163
|
|
164
|
+
describe "#worker_class_name" do
|
165
|
+
it "returns class_name from worker/proxy" do
|
166
|
+
allow(proxy).to receive(:class_name).and_return('barkle rutfut')
|
167
|
+
expect(subject.worker_class_name).to eq('barkle rutfut')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "#uptime" do
|
172
|
+
it "returns difference between now and updated_at" do
|
173
|
+
frozen_time = Time.now
|
174
|
+
allow(Time).to receive(:now).and_return(frozen_time)
|
175
|
+
expect(subject.uptime).to eq(frozen_time - subject.launched_at)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "returns previous persisted uptime if stopped" do
|
179
|
+
allow(proxy).to receive(:state).and_return("stopped")
|
180
|
+
expect(subject.uptime).to eq(proxy.uptime)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
131
184
|
describe "#updated_at" do
|
132
185
|
it "returns parsed put_at from raw hash for worker" do
|
133
186
|
allow(subject).to receive(:raw_hash).and_return({
|
@@ -175,8 +228,8 @@ describe Bumbleworks::Worker::Info do
|
|
175
228
|
describe "#raw_hash" do
|
176
229
|
it "returns value from worker_info hash at key of worker id" do
|
177
230
|
allow(described_class).to receive(:raw_hash).and_return({
|
178
|
-
|
179
|
-
|
231
|
+
"f_id" => :foo_hash,
|
232
|
+
"b_id" => :bar_hash
|
180
233
|
})
|
181
234
|
expect(subject.raw_hash).to eq(:foo_hash)
|
182
235
|
end
|
@@ -194,6 +247,28 @@ describe Bumbleworks::Worker::Info do
|
|
194
247
|
end
|
195
248
|
end
|
196
249
|
|
250
|
+
describe "#in_stopped_state?" do
|
251
|
+
it "returns true if state is stopped" do
|
252
|
+
allow(proxy).to receive(:state).and_return("stopped")
|
253
|
+
expect(subject).to be_in_stopped_state
|
254
|
+
end
|
255
|
+
|
256
|
+
it "returns true if state is stalled" do
|
257
|
+
allow(proxy).to receive(:state).and_return("stalled")
|
258
|
+
expect(subject).to be_in_stopped_state
|
259
|
+
end
|
260
|
+
|
261
|
+
it "returns true if state is nil" do
|
262
|
+
allow(proxy).to receive(:state).and_return(nil)
|
263
|
+
expect(subject).to be_in_stopped_state
|
264
|
+
end
|
265
|
+
|
266
|
+
it "returns false if state is running" do
|
267
|
+
allow(proxy).to receive(:state).and_return("running")
|
268
|
+
expect(subject).not_to be_in_stopped_state
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
197
272
|
describe "#stalling?" do
|
198
273
|
it "returns inverse of #responding?" do
|
199
274
|
allow(subject).to receive(:responding?).and_return(true)
|
@@ -202,4 +277,96 @@ describe Bumbleworks::Worker::Info do
|
|
202
277
|
expect(subject).to be_stalling
|
203
278
|
end
|
204
279
|
end
|
280
|
+
|
281
|
+
context "worker control commands" do
|
282
|
+
subject { Bumbleworks::Worker::Info.first }
|
283
|
+
let(:other_worker) { Bumbleworks::Worker::Info.all[1] }
|
284
|
+
before(:each) do
|
285
|
+
2.times { Bumbleworks.start_worker! }
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "#shutdown" do
|
289
|
+
it "shuts down just this worker" do
|
290
|
+
subject.shutdown
|
291
|
+
expect(subject.state).to eq("stopped")
|
292
|
+
expect(other_worker.state).to eq("running")
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe "#pause" do
|
297
|
+
it "pauses just this worker" do
|
298
|
+
subject.pause
|
299
|
+
expect(subject.state).to eq("paused")
|
300
|
+
expect(other_worker.state).to eq("running")
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
describe "#unpause" do
|
305
|
+
it "unpauses just this worker" do
|
306
|
+
[subject, other_worker].map(&:pause)
|
307
|
+
subject.unpause
|
308
|
+
expect(subject.state).to eq("running")
|
309
|
+
expect(other_worker.state).to eq("paused")
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe "#run" do
|
314
|
+
it "is an alias for unpause" do
|
315
|
+
expect(subject.method(:run)).to eq(subject.method(:unpause))
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "#reload" do
|
321
|
+
it "generates a new proxy from the current raw hash" do
|
322
|
+
Bumbleworks.start_worker!
|
323
|
+
subject = Bumbleworks::Worker::Info.first
|
324
|
+
expect(Bumbleworks::Worker::Proxy).to receive(:new).
|
325
|
+
with(subject.raw_hash).and_return(:a_worker)
|
326
|
+
subject.reload
|
327
|
+
expect(subject.worker).to eq(:a_worker)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe "#record_new_state" do
|
332
|
+
it "saves new state" do
|
333
|
+
expect(subject.worker).to receive(:state=).with("an awesome state").ordered
|
334
|
+
expect(subject).to receive(:save).ordered
|
335
|
+
subject.record_new_state("an awesome state")
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
describe "#save" do
|
340
|
+
before(:each) { Bumbleworks.start_worker! }
|
341
|
+
subject { Bumbleworks::Worker::Info.first }
|
342
|
+
|
343
|
+
it "persists all data unchanged to the engine storage" do
|
344
|
+
expected_hash = subject.constant_worker_info_hash
|
345
|
+
subject.save
|
346
|
+
expect(described_class[subject.id.to_s].constant_worker_info_hash).to eq(expected_hash)
|
347
|
+
end
|
348
|
+
|
349
|
+
it "updates uptime and updated_at even without changed data" do
|
350
|
+
uptime, updated_at = subject.uptime, subject.updated_at
|
351
|
+
subject.save
|
352
|
+
expect(described_class[subject.id.to_s].uptime).not_to eq(uptime)
|
353
|
+
expect(described_class[subject.id.to_s].updated_at).not_to eq(updated_at)
|
354
|
+
end
|
355
|
+
|
356
|
+
it "persists changed data" do
|
357
|
+
expected_hash = subject.constant_worker_info_hash
|
358
|
+
subject.worker.instance_variable_set(:@pid, "12345")
|
359
|
+
subject.save
|
360
|
+
expect(described_class[subject.id.to_s].id).to eq(expected_hash["id"])
|
361
|
+
expect(described_class[subject.id.to_s].pid).to eq("12345")
|
362
|
+
end
|
363
|
+
|
364
|
+
it "does not update uptime if worker is stopped" do
|
365
|
+
allow_any_instance_of(Bumbleworks::Worker::Proxy).to receive(:state).
|
366
|
+
and_return("stopped")
|
367
|
+
uptime = subject.uptime
|
368
|
+
subject.save
|
369
|
+
expect(described_class[subject.id.to_s].uptime).to eq(uptime)
|
370
|
+
end
|
371
|
+
end
|
205
372
|
end
|
@@ -9,14 +9,39 @@ describe Bumbleworks::Worker::Proxy do
|
|
9
9
|
'ip' => :f_ip,
|
10
10
|
'hostname' => :f_hostname,
|
11
11
|
'system' => :f_system,
|
12
|
-
'launched_at' => :
|
12
|
+
'launched_at' => '2010-10-10 10:10:10'
|
13
13
|
)
|
14
14
|
}
|
15
15
|
|
16
16
|
describe "#launched_at" do
|
17
|
+
let(:expected_time) { Time.parse('2010-10-10 10:10:10') }
|
18
|
+
|
17
19
|
it "returns initialized launched_at string parsed as Time" do
|
18
|
-
|
19
|
-
|
20
|
+
expect(subject.launched_at).to eq(expected_time)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns launched_at directly if already Time" do
|
24
|
+
subject.instance_variable_set(:@launched_at, expected_time)
|
25
|
+
expect(subject.launched_at).to eq(expected_time)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#class_name" do
|
30
|
+
it "returns class passed in from hash" do
|
31
|
+
expect(subject.class_name).to eq("f_class")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#storage" do
|
36
|
+
it "returns nil to allow default" do
|
37
|
+
expect(subject.storage).to be_nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#state=" do
|
42
|
+
it "changes the proxy's recorded state" do
|
43
|
+
subject.state = "flummoxing"
|
44
|
+
expect(subject.state).to eq("flummoxing")
|
20
45
|
end
|
21
46
|
end
|
22
47
|
end
|
@@ -17,42 +17,45 @@ describe Bumbleworks::Worker do
|
|
17
17
|
|
18
18
|
context 'with multiple workers' do
|
19
19
|
let!(:workers) {
|
20
|
-
|
20
|
+
3.times.map { |i|
|
21
21
|
worker = described_class.new(context)
|
22
22
|
worker.run_in_thread
|
23
23
|
worker
|
24
24
|
}
|
25
25
|
}
|
26
26
|
|
27
|
-
describe '.
|
27
|
+
describe '.active_worker_states' do
|
28
28
|
it 'returns the states of all active workers' do
|
29
29
|
subject.run_in_thread
|
30
|
-
expect(described_class.
|
30
|
+
expect(described_class.active_worker_states).to eq({
|
31
31
|
subject.id => 'running',
|
32
32
|
workers[0].id => 'running',
|
33
|
-
workers[1].id => 'running'
|
33
|
+
workers[1].id => 'running',
|
34
|
+
workers[2].id => 'running'
|
34
35
|
})
|
35
36
|
end
|
36
37
|
|
37
|
-
it 'does not include stopped or nil states' do
|
38
|
+
it 'does not include stopped, stalled, or nil states' do
|
38
39
|
subject.run_in_thread
|
39
40
|
workers[0].shutdown
|
40
41
|
workers[1].instance_variable_set(:@state, nil)
|
41
42
|
workers[1].instance_variable_get(:@info).save
|
42
|
-
|
43
|
+
workers[2].instance_variable_set(:@state, "stalled")
|
44
|
+
workers[2].instance_variable_get(:@info).save
|
45
|
+
expect(described_class.active_worker_states).to eq({
|
43
46
|
subject.id => 'running'
|
44
47
|
})
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
48
51
|
describe '.refresh_worker_info' do
|
49
|
-
it 'times out
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
expect
|
54
|
-
|
55
|
-
|
52
|
+
it 'times out and marks worker stalled if stalling' do
|
53
|
+
info1 = double(:in_stopped_state? => false, :stalling? => true)
|
54
|
+
info2 = double(:in_stopped_state? => false, :stalling? => false)
|
55
|
+
allow(described_class).to receive(:info).and_return([info1, info2])
|
56
|
+
expect(info1).to receive(:record_new_state).with("stalled")
|
57
|
+
expect(info2).to receive(:record_new_state).never
|
58
|
+
described_class.refresh_worker_info(:timeout => 0.1)
|
56
59
|
end
|
57
60
|
|
58
61
|
it 'refreshes worker info' do
|
@@ -61,11 +64,11 @@ describe Bumbleworks::Worker do
|
|
61
64
|
doc['workers'][subject.id]['put_at'] = (Time.now - 30).to_s
|
62
65
|
subject.storage.put(doc)
|
63
66
|
described_class.refresh_worker_info
|
64
|
-
expect(
|
67
|
+
expect(subject.info.updated_at).to be_within(1).of(Time.now)
|
65
68
|
end
|
66
69
|
|
67
70
|
it 'returns without issue if info empty' do
|
68
|
-
allow(described_class).to receive(:info).and_return(
|
71
|
+
allow(described_class).to receive(:info).and_return([])
|
69
72
|
expect {
|
70
73
|
described_class.refresh_worker_info
|
71
74
|
}.not_to raise_error
|
@@ -87,12 +90,14 @@ describe Bumbleworks::Worker do
|
|
87
90
|
}.to raise_error(described_class::WorkerStateNotChanged)
|
88
91
|
end
|
89
92
|
|
90
|
-
it 'ignores already stopped workers' do
|
93
|
+
it 'ignores already stopped or stalled workers' do
|
91
94
|
described_class.shutdown_all
|
95
|
+
workers[2].instance_variable_set(:@state, "stalled")
|
96
|
+
workers[2].instance_variable_get(:@info).save
|
92
97
|
subject.run_in_thread
|
93
98
|
described_class.change_worker_state('paused')
|
94
99
|
expect(subject.state).to eq('paused')
|
95
|
-
expect(workers.map(&:state)).to eq(['stopped', 'stopped'])
|
100
|
+
expect(workers.map(&:state)).to eq(['stopped', 'stopped', 'stalled'])
|
96
101
|
end
|
97
102
|
|
98
103
|
it 'does nothing if no worker info' do
|
@@ -110,6 +115,13 @@ describe Bumbleworks::Worker do
|
|
110
115
|
expect(described_class).to receive(:change_worker_state).with('running', {}).ordered
|
111
116
|
described_class.shutdown_all
|
112
117
|
end
|
118
|
+
|
119
|
+
it 'resets to running even if error occurred when attempting stop' do
|
120
|
+
expect(described_class).to receive(:change_worker_state).with('stopped', {}).ordered.
|
121
|
+
and_raise('an interruption')
|
122
|
+
expect(described_class).to receive(:change_worker_state).with('running', {}).ordered
|
123
|
+
expect { described_class.shutdown_all }.to raise_error('an interruption')
|
124
|
+
end
|
113
125
|
end
|
114
126
|
|
115
127
|
describe '.pause_all' do
|
@@ -138,4 +150,10 @@ describe Bumbleworks::Worker do
|
|
138
150
|
expect(subject.info).to eq(described_class.info[subject.id])
|
139
151
|
end
|
140
152
|
end
|
153
|
+
|
154
|
+
describe "#class_name" do
|
155
|
+
it "returns string version of class" do
|
156
|
+
expect(subject.class_name).to eq(subject.class.to_s)
|
157
|
+
end
|
158
|
+
end
|
141
159
|
end
|
@@ -1,20 +1,3 @@
|
|
1
|
-
shared_examples "an entity holder" do
|
2
|
-
[:has_entity_fields?, :has_entity?, :entity, :entity_fields, :entity_name].each do |method|
|
3
|
-
describe "##{method}" do
|
4
|
-
it 'delegates to entity storage workitem' do
|
5
|
-
allow(holder.entity_storage_workitem).to receive(method).with(1, 2, 3).and_return(:yay_for_bikes)
|
6
|
-
expect(holder.send(method, 1, 2, 3)).to eq(:yay_for_bikes)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
describe "#entity_storage_workitem" do
|
12
|
-
it 'returns the expected workitem' do
|
13
|
-
expect(holder.entity_storage_workitem).to eq(storage_workitem)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
1
|
shared_examples "comparable" do
|
19
2
|
describe "#hash" do
|
20
3
|
it 'returns hash of identifier_for_comparison' do
|
@@ -0,0 +1,16 @@
|
|
1
|
+
shared_examples "an entity holder" do
|
2
|
+
[:has_entity_fields?, :has_entity?, :entity, :entity_fields, :entity_name].each do |method|
|
3
|
+
describe "##{method}" do
|
4
|
+
it 'delegates to entity storage workitem' do
|
5
|
+
allow(holder.entity_storage_workitem).to receive(method).with(1, 2, 3).and_return(:yay_for_bikes)
|
6
|
+
expect(holder.send(method, 1, 2, 3)).to eq(:yay_for_bikes)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#entity_storage_workitem" do
|
12
|
+
it 'returns the expected workitem' do
|
13
|
+
expect(holder.entity_storage_workitem).to eq(storage_workitem)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bumbleworks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.91
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maher Hawash
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-03-
|
14
|
+
date: 2015-03-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: ruote
|
@@ -139,6 +139,7 @@ files:
|
|
139
139
|
- ".gitignore"
|
140
140
|
- ".rspec"
|
141
141
|
- ".ruby-version"
|
142
|
+
- ".travis.yml"
|
142
143
|
- ".watchr"
|
143
144
|
- Gemfile
|
144
145
|
- LICENSE.txt
|
@@ -245,9 +246,12 @@ files:
|
|
245
246
|
- spec/lib/bumbleworks/workitem_spec.rb
|
246
247
|
- spec/lib/bumbleworks_spec.rb
|
247
248
|
- spec/spec_helper.rb
|
249
|
+
- spec/support/matchers/delegation_matcher.rb
|
250
|
+
- spec/support/matchers/fetch_matcher.rb
|
248
251
|
- spec/support/path_helpers.rb
|
249
252
|
- spec/support/process_testing_helpers.rb
|
250
|
-
- spec/support/shared_examples.rb
|
253
|
+
- spec/support/shared_examples/comparable.rb
|
254
|
+
- spec/support/shared_examples/entity_holder.rb
|
251
255
|
- spec/support/tracer.rb
|
252
256
|
homepage: ''
|
253
257
|
licenses:
|
@@ -331,7 +335,10 @@ test_files:
|
|
331
335
|
- spec/lib/bumbleworks/workitem_spec.rb
|
332
336
|
- spec/lib/bumbleworks_spec.rb
|
333
337
|
- spec/spec_helper.rb
|
338
|
+
- spec/support/matchers/delegation_matcher.rb
|
339
|
+
- spec/support/matchers/fetch_matcher.rb
|
334
340
|
- spec/support/path_helpers.rb
|
335
341
|
- spec/support/process_testing_helpers.rb
|
336
|
-
- spec/support/shared_examples.rb
|
342
|
+
- spec/support/shared_examples/comparable.rb
|
343
|
+
- spec/support/shared_examples/entity_holder.rb
|
337
344
|
- spec/support/tracer.rb
|