bumbleworks 0.0.90 → 0.0.91
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.
- 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
|