background_queue 0.3.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|