background_queue 0.3.0 → 0.6.0
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.
- data/TODO +13 -0
- data/VERSION +1 -1
- data/background_queue.gemspec +8 -2
- data/lib/background_queue/client.rb +31 -3
- data/lib/background_queue/client_lib/connection.rb +9 -0
- data/lib/background_queue/client_lib/job_handle.rb +34 -1
- data/lib/background_queue/config.rb +1 -11
- data/lib/background_queue/server_lib/balanced_queue.rb +22 -0
- data/lib/background_queue/server_lib/event_connection.rb +7 -1
- data/lib/background_queue/server_lib/job.rb +46 -7
- data/lib/background_queue/server_lib/priority_queue.rb +7 -0
- data/lib/background_queue/server_lib/queue_registry.rb +20 -5
- data/lib/background_queue/server_lib/task.rb +28 -0
- data/lib/background_queue/server_lib/task_registry.rb +7 -0
- data/lib/background_queue/server_lib/worker_client.rb +5 -2
- data/lib/background_queue/server_lib/worker_thread.rb +1 -1
- data/lib/background_queue/utils.rb +25 -1
- data/lib/background_queue/worker/base.rb +41 -0
- data/lib/background_queue/worker/calling.rb +24 -1
- data/lib/background_queue/worker/config.rb +20 -0
- data/lib/background_queue/worker/environment.rb +25 -1
- data/lib/background_queue/worker/logger.rb +114 -0
- data/lib/background_queue/worker/progress.rb +152 -0
- data/lib/background_queue/worker/worker_loader.rb +1 -1
- data/lib/background_queue_worker.rb +2 -0
- data/spec/background_queue/client_lib/connection_spec.rb +7 -1
- data/spec/background_queue/client_spec.rb +2 -1
- data/spec/background_queue/config_spec.rb +11 -23
- data/spec/background_queue/server_lib/integration/error_handling_spec.rb +85 -0
- data/spec/background_queue/server_lib/integration/full_test_spec.rb +76 -3
- data/spec/background_queue/server_lib/integration/queue_integration_spec.rb +6 -3
- data/spec/background_queue/server_lib/job_spec.rb +44 -3
- data/spec/background_queue/server_lib/worker_thread_spec.rb +2 -2
- data/spec/background_queue/utils_spec.rb +30 -0
- data/spec/background_queue/worker/calling_spec.rb +3 -1
- data/spec/background_queue/worker/environment_spec.rb +3 -1
- data/spec/background_queue/worker/logger_spec.rb +58 -0
- data/spec/background_queue/worker/progress_spec.rb +82 -0
- data/spec/background_queue/worker/worker_loader_spec.rb +1 -1
- data/spec/resources/summary_worker.rb +18 -0
- data/spec/shared/queue_registry_shared.rb +4 -3
- data/spec/support/simple_task.rb +24 -0
- metadata +33 -27
@@ -0,0 +1,152 @@
|
|
1
|
+
module BackgroundQueue::Worker
|
2
|
+
#a way of notifying worker progress
|
3
|
+
class Progress
|
4
|
+
|
5
|
+
attr_reader :registered_tasks
|
6
|
+
|
7
|
+
def initialize(callback_object)
|
8
|
+
if callback_object.kind_of?(BackgroundQueue::Worker::Base)
|
9
|
+
@worker = callback_object
|
10
|
+
elsif callback_object.kind_of?(Proc)
|
11
|
+
@callback = callback_object
|
12
|
+
else
|
13
|
+
@callback_object = callback_object
|
14
|
+
end
|
15
|
+
|
16
|
+
@main_caption = nil
|
17
|
+
@sub_caption = nil
|
18
|
+
|
19
|
+
@finished_sub_progress = 0
|
20
|
+
@current_sub_progress_size = 0
|
21
|
+
@current_sub_progress = 0
|
22
|
+
@sub_task_step_size = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(main_caption=nil)
|
26
|
+
@main_caption = main_caption
|
27
|
+
|
28
|
+
@sub_caption = nil
|
29
|
+
|
30
|
+
@finished_sub_progress = 0
|
31
|
+
@current_sub_progress_size = 0
|
32
|
+
@current_sub_progress = 0
|
33
|
+
|
34
|
+
update_callback
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_main_caption(caption)
|
38
|
+
@main_caption = caption
|
39
|
+
update_callback
|
40
|
+
end
|
41
|
+
|
42
|
+
def finish(main_caption = nil)
|
43
|
+
@main_caption = main_caption unless main_caption.nil?
|
44
|
+
@sub_caption = nil unless main_caption.nil?
|
45
|
+
@current_sub_progress = 0
|
46
|
+
@finished_sub_progress = 100
|
47
|
+
update_callback
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def register_task(key, units)
|
52
|
+
@registered_tasks ||= {}
|
53
|
+
@registered_task_total ||= 0
|
54
|
+
@registered_tasks[key] = units
|
55
|
+
@registered_task_total += units
|
56
|
+
end
|
57
|
+
|
58
|
+
def start_task(key, caption=nil)
|
59
|
+
if @current_sub_progress_size != 0
|
60
|
+
@finished_sub_progress += @current_sub_progress_size
|
61
|
+
@current_sub_progress_size = 0
|
62
|
+
end
|
63
|
+
@current_sub_progress_size = get_task_size(key)
|
64
|
+
@current_sub_progress = 0.0
|
65
|
+
@sub_task_step_size = 0
|
66
|
+
@sub_caption = caption
|
67
|
+
update_callback
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_task_size(key)
|
71
|
+
raise "No registered sub task (#{key})" if @registered_tasks[key].nil?
|
72
|
+
@registered_tasks[key].to_f / @registered_task_total * 100.0
|
73
|
+
end
|
74
|
+
|
75
|
+
def set_task_steps(step_count)
|
76
|
+
if step_count == 0
|
77
|
+
@sub_task_step_size = 100
|
78
|
+
else
|
79
|
+
@sub_task_step_size = 100.0 / step_count.to_f * 100.0
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def inc
|
84
|
+
@current_sub_progress += @sub_task_step_size
|
85
|
+
update_callback
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_task_progress(percent)
|
89
|
+
@current_sub_progress += percent
|
90
|
+
@current_sub_progress = 100 if @current_sub_progress > 100
|
91
|
+
update_callback
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_task_caption(caption)
|
95
|
+
@sub_caption = caption
|
96
|
+
update_callback
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_note(notice)
|
100
|
+
update_callback_meta(:notice, notice)
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_warning(warning)
|
104
|
+
update_callback_meta(:warning, warning)
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_error(error)
|
108
|
+
update_callback_meta(:error, error)
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_meta_data(key, data)
|
112
|
+
update_callback_meta(:meta, {key=>data})
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_caption
|
116
|
+
if @main_caption && @sub_caption
|
117
|
+
"#{@main_caption}: #{@sub_caption }"
|
118
|
+
elsif @main_caption
|
119
|
+
@main_caption
|
120
|
+
elsif @sub_caption
|
121
|
+
@sub_caption
|
122
|
+
else
|
123
|
+
""
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_percent
|
128
|
+
@finished_sub_progress + (@current_sub_progress_size / 100.0 * @current_sub_progress / 100.0)
|
129
|
+
end
|
130
|
+
|
131
|
+
def update_callback
|
132
|
+
if @worker
|
133
|
+
@worker.set_progress(get_caption, get_percent)
|
134
|
+
elsif @callback
|
135
|
+
@callback.call(:progress, get_caption, get_percent)
|
136
|
+
elsif @callback_object
|
137
|
+
@callback_object.set_progress(get_caption, get_percent, self)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_callback_meta(key, value)
|
142
|
+
if @worker
|
143
|
+
@worker.add_progress_meta(key, value)
|
144
|
+
elsif @callback
|
145
|
+
@callback.call(:meta, key, value)
|
146
|
+
elsif @callback_object
|
147
|
+
@callback_object.add_progress_meta(key, value, self)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
end
|
@@ -56,7 +56,7 @@ module BackgroundQueue::Worker
|
|
56
56
|
ds = File.mtime(worker_entry.path)
|
57
57
|
if ds != worker_entry.datestamp
|
58
58
|
load_file(worker_entry.path)
|
59
|
-
worker_entry.worker = load_class(worker_entry.name)
|
59
|
+
worker_entry.worker = load_class(worker_entry.name, worker_entry.path)
|
60
60
|
worker_entry.datestamp = ds
|
61
61
|
end
|
62
62
|
end
|
@@ -9,6 +9,10 @@ describe "Connection" do
|
|
9
9
|
svr
|
10
10
|
}
|
11
11
|
|
12
|
+
let(:socket) {
|
13
|
+
double("socket")
|
14
|
+
}
|
15
|
+
|
12
16
|
|
13
17
|
|
14
18
|
context "connecting" do
|
@@ -16,7 +20,8 @@ describe "Connection" do
|
|
16
20
|
subject { BackgroundQueue::ClientLib::Connection.new(:client, server) }
|
17
21
|
|
18
22
|
it "can successfully connect" do
|
19
|
-
|
23
|
+
socket.should_receive(:setsockopt)
|
24
|
+
TCPSocket.should_receive(:open).with(:host, :port) { socket }
|
20
25
|
subject.__prv__connect.should eq(true)
|
21
26
|
end
|
22
27
|
|
@@ -38,6 +43,7 @@ describe "Connection" do
|
|
38
43
|
subject {
|
39
44
|
s = BackgroundQueue::ClientLib::Connection.new(:client, server)
|
40
45
|
TCPSocket.should_receive(:open).with(:host, :port) { socket }
|
46
|
+
socket.should_receive(:setsockopt)
|
41
47
|
s.__prv__connect
|
42
48
|
s
|
43
49
|
}
|
@@ -72,7 +72,8 @@ describe "Client" do
|
|
72
72
|
end
|
73
73
|
|
74
74
|
it "can build and send an add tasks command" do
|
75
|
-
subject.add_tasks(:worker, :owner_id, :job_id, :tasks, 1, {}, {} )
|
75
|
+
job_handle = subject.add_tasks(:worker, :owner_id, :job_id, :tasks, 1, {}, {} )
|
76
|
+
job_handle.job_id.should eq(:job_id)
|
76
77
|
end
|
77
78
|
|
78
79
|
|
@@ -57,38 +57,26 @@ describe "Config" do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
BackgroundQueue::Config.__prv__current_environment.should eq(:the_env)
|
60
|
+
|
61
|
+
context "with development environment" do
|
62
|
+
before do
|
63
|
+
BackgroundQueue::Utils.stub(:current_environment) { 'development' }
|
65
64
|
end
|
66
65
|
|
67
|
-
it "
|
68
|
-
|
69
|
-
Rails.should_receive(:env) { :the_env }
|
70
|
-
BackgroundQueue::Config.__prv__current_environment.should eq(:the_env)
|
66
|
+
it "extracts the correct environment entry from the hash" do
|
67
|
+
BackgroundQueue::Config.__prv__extract_enviroment_entry({:development=>:test}, :path_that_exists).should eq(:test)
|
71
68
|
end
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
it "extracts the correct environment entry from the hash" do
|
79
|
-
BackgroundQueue::Config.__prv__extract_enviroment_entry({:development=>:test}, :path_that_exists).should eq(:test)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "errors if the YAML does not define environment entry" do
|
83
|
-
File.stub(:expand_path) { :expanded_path }
|
84
|
-
expect { BackgroundQueue::Config.__prv__extract_enviroment_entry({:test=>:test}, :path_that_exists).should eq(:test)}.to raise_error(BackgroundQueue::LoadError, "Error loading YAML for background_queue configuration file at 'expanded_path': missing enviroment root entry: development")
|
85
|
-
end
|
70
|
+
it "errors if the YAML does not define environment entry" do
|
71
|
+
File.stub(:expand_path) { :expanded_path }
|
72
|
+
expect { BackgroundQueue::Config.__prv__extract_enviroment_entry({:test=>:test}, :path_that_exists).should eq(:test)}.to raise_error(BackgroundQueue::LoadError, "Error loading YAML for background_queue configuration file at 'expanded_path': missing enviroment root entry: development")
|
86
73
|
end
|
87
74
|
end
|
75
|
+
|
88
76
|
|
89
77
|
context "with extracted environment entry" do
|
90
78
|
before do
|
91
|
-
BackgroundQueue::
|
79
|
+
BackgroundQueue::Utils.stub(:current_environment) { 'development' }
|
92
80
|
end
|
93
81
|
it "calls load using map" do
|
94
82
|
BackgroundQueue::Config.should_receive(:load_hash).with({'a'=>'b'}, :path_that_exists) { true }
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
|
2
|
+
require 'background_queue_server'
|
3
|
+
require 'background_queue'
|
4
|
+
require 'background_queue_worker'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
gem "rufus-scheduler"
|
9
|
+
|
10
|
+
#unless defined? Rails
|
11
|
+
module Rails;
|
12
|
+
def self.env
|
13
|
+
"development"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
#end
|
17
|
+
|
18
|
+
describe "Error Handling Test" do
|
19
|
+
|
20
|
+
context "same task" do
|
21
|
+
|
22
|
+
it "will add tasks to an error list" do
|
23
|
+
|
24
|
+
config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config.yml')
|
25
|
+
|
26
|
+
server = BackgroundQueue::ServerLib::Server.new
|
27
|
+
|
28
|
+
thread = Thread.new {
|
29
|
+
server.start(:config=>config_path, :skip_pid=>true, :command=>:run, :log_file=>"/tmp/bq.log", :log_level=>'debug')
|
30
|
+
}
|
31
|
+
|
32
|
+
while server.event_server.nil? || !server.event_server.running
|
33
|
+
sleep(0.1)
|
34
|
+
end
|
35
|
+
ss = nil
|
36
|
+
begin
|
37
|
+
|
38
|
+
meth_name = nil
|
39
|
+
ss = TestWorkerServer.new(8001)
|
40
|
+
attempt_count = 0
|
41
|
+
ss.start(Proc.new { |controller|
|
42
|
+
meth_name = controller.request.request_method
|
43
|
+
attempt_count += 1
|
44
|
+
if attempt_count < 3
|
45
|
+
controller.render :text=>"ARGH", :type=>"text/text", :status=>500
|
46
|
+
else
|
47
|
+
controller.render :text=>{:percent=>100, :caption=>"Done"}.to_json, :type=>"text/text"
|
48
|
+
end
|
49
|
+
})
|
50
|
+
|
51
|
+
|
52
|
+
client_config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-client.yml')
|
53
|
+
|
54
|
+
client = BackgroundQueue::Client.new(client_config_path)
|
55
|
+
|
56
|
+
|
57
|
+
job_handle = client.add_task(:some_worker, :owner_id, :job_id, :task_id, 2, {:something=>:else}, {:domain=>"www.example.com"} )
|
58
|
+
|
59
|
+
|
60
|
+
ss.wait_to_be_called.should be_true
|
61
|
+
|
62
|
+
#add same task while in existing in error state
|
63
|
+
job_handle = client.add_task(:some_worker, :owner_id, :job_id, :task_id, 2, {:something=>:else}, {:domain=>"www.example.com"} )
|
64
|
+
|
65
|
+
ss.wait_to_be_called.should be_true
|
66
|
+
ss.wait_to_be_called.should be_true
|
67
|
+
|
68
|
+
result = client.get_status(job_handle)
|
69
|
+
|
70
|
+
result.code.should eq(:status)
|
71
|
+
result.args[:percent].should eq(100)
|
72
|
+
result.args[:caption].should eq('Done')
|
73
|
+
|
74
|
+
|
75
|
+
ensure
|
76
|
+
ss.stop unless ss.nil?
|
77
|
+
server.stop
|
78
|
+
|
79
|
+
thread.join
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -92,7 +92,7 @@ describe "Full Test" do
|
|
92
92
|
while server.event_server.nil? || !server.event_server.running
|
93
93
|
sleep(0.1)
|
94
94
|
end
|
95
|
-
|
95
|
+
ss = nil
|
96
96
|
begin
|
97
97
|
|
98
98
|
task_pos = 0
|
@@ -149,7 +149,7 @@ describe "Full Test" do
|
|
149
149
|
meth_name.should eq("POST")
|
150
150
|
|
151
151
|
stats = client.get_stats(job_handle.server)
|
152
|
-
stats[:running].should eq(
|
152
|
+
stats[:running].should eq(2)
|
153
153
|
stats[:run_tasks].should eq(1)
|
154
154
|
|
155
155
|
#pp server
|
@@ -180,8 +180,9 @@ describe "Full Test" do
|
|
180
180
|
stats[:running].should eq(0)
|
181
181
|
stats[:run_tasks].should eq(3)
|
182
182
|
|
183
|
-
|
183
|
+
|
184
184
|
ensure
|
185
|
+
ss.stop unless ss.nil?
|
185
186
|
server.stop
|
186
187
|
thread.join
|
187
188
|
end
|
@@ -243,5 +244,77 @@ describe "Full Test" do
|
|
243
244
|
end
|
244
245
|
end
|
245
246
|
|
247
|
+
|
248
|
+
it "will keep track of summary" do
|
249
|
+
|
250
|
+
config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config.yml')
|
251
|
+
BackgroundQueue::Worker::Config.worker_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/')
|
252
|
+
BackgroundQueue::Worker::Config.secret = "this_is_used_to_make_sure_it_is_secure"
|
253
|
+
|
254
|
+
server = BackgroundQueue::ServerLib::Server.new
|
255
|
+
|
256
|
+
thread = Thread.new {
|
257
|
+
server.start(:config=>config_path, :skip_pid=>true, :command=>:run, :log_file=>"/tmp/bq.log", :log_level=>'debug')
|
258
|
+
}
|
259
|
+
|
260
|
+
while server.event_server.nil? || !server.event_server.running
|
261
|
+
sleep(0.1)
|
262
|
+
end
|
263
|
+
|
264
|
+
begin
|
265
|
+
|
266
|
+
count = 0
|
267
|
+
summary_data = nil
|
268
|
+
meth_name = nil
|
269
|
+
ss = TestWorkerServer.new(8001, true)
|
270
|
+
ss.start(Proc.new { |controller|
|
271
|
+
controller.class.send(:include, BackgroundQueue::Worker::Calling)
|
272
|
+
controller.run_worker
|
273
|
+
})
|
274
|
+
|
275
|
+
|
276
|
+
client_config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-client.yml')
|
277
|
+
|
278
|
+
client = BackgroundQueue::Client.new(client_config_path)
|
279
|
+
|
280
|
+
|
281
|
+
job_handle = client.add_tasks(:summary_worker, :owner_id, :job_id, [[:task1_id, {:test_id=>1}], [:task2_id, {:test_id=>2}], [:task3_id, {:mode=>"summary"}, {:send_summary=>true, :weight=>10, :exclude=>true, :synchronous=>true}]], 2, {:something=>:else}, {:domain=>"www.example.com"} )
|
282
|
+
|
283
|
+
ss.allow_to_be_called
|
284
|
+
ss.wait_to_be_called.should be_true
|
285
|
+
|
286
|
+
result = client.get_status(job_handle)
|
287
|
+
|
288
|
+
result.code.should eq(:status)
|
289
|
+
result.args[:percent].should eq(45)
|
290
|
+
result.args[:caption].should eq('Done (2/2)')
|
291
|
+
result.args[:meta].should eq({'test_meta'=>"something"})
|
292
|
+
|
293
|
+
ss.allow_to_be_called
|
294
|
+
ss.wait_to_be_called.should be_true
|
295
|
+
|
296
|
+
result = client.get_status(job_handle)
|
297
|
+
|
298
|
+
result.code.should eq(:status)
|
299
|
+
result.args[:percent].should eq(90)
|
300
|
+
result.args[:caption].should eq('Done (2/2)')
|
301
|
+
|
302
|
+
ss.allow_to_be_called
|
303
|
+
ss.wait_to_be_called.should be_true
|
304
|
+
|
305
|
+
result = client.get_status(job_handle)
|
306
|
+
|
307
|
+
result.code.should eq(:status)
|
308
|
+
result.args[:percent].should eq(100)
|
309
|
+
result.args[:caption].should eq('Done')
|
310
|
+
|
311
|
+
ss.stop
|
312
|
+
ensure
|
313
|
+
server.stop
|
314
|
+
|
315
|
+
thread.join
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
246
319
|
end
|
247
320
|
end
|