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.
Files changed (43) hide show
  1. data/TODO +13 -0
  2. data/VERSION +1 -1
  3. data/background_queue.gemspec +8 -2
  4. data/lib/background_queue/client.rb +31 -3
  5. data/lib/background_queue/client_lib/connection.rb +9 -0
  6. data/lib/background_queue/client_lib/job_handle.rb +34 -1
  7. data/lib/background_queue/config.rb +1 -11
  8. data/lib/background_queue/server_lib/balanced_queue.rb +22 -0
  9. data/lib/background_queue/server_lib/event_connection.rb +7 -1
  10. data/lib/background_queue/server_lib/job.rb +46 -7
  11. data/lib/background_queue/server_lib/priority_queue.rb +7 -0
  12. data/lib/background_queue/server_lib/queue_registry.rb +20 -5
  13. data/lib/background_queue/server_lib/task.rb +28 -0
  14. data/lib/background_queue/server_lib/task_registry.rb +7 -0
  15. data/lib/background_queue/server_lib/worker_client.rb +5 -2
  16. data/lib/background_queue/server_lib/worker_thread.rb +1 -1
  17. data/lib/background_queue/utils.rb +25 -1
  18. data/lib/background_queue/worker/base.rb +41 -0
  19. data/lib/background_queue/worker/calling.rb +24 -1
  20. data/lib/background_queue/worker/config.rb +20 -0
  21. data/lib/background_queue/worker/environment.rb +25 -1
  22. data/lib/background_queue/worker/logger.rb +114 -0
  23. data/lib/background_queue/worker/progress.rb +152 -0
  24. data/lib/background_queue/worker/worker_loader.rb +1 -1
  25. data/lib/background_queue_worker.rb +2 -0
  26. data/spec/background_queue/client_lib/connection_spec.rb +7 -1
  27. data/spec/background_queue/client_spec.rb +2 -1
  28. data/spec/background_queue/config_spec.rb +11 -23
  29. data/spec/background_queue/server_lib/integration/error_handling_spec.rb +85 -0
  30. data/spec/background_queue/server_lib/integration/full_test_spec.rb +76 -3
  31. data/spec/background_queue/server_lib/integration/queue_integration_spec.rb +6 -3
  32. data/spec/background_queue/server_lib/job_spec.rb +44 -3
  33. data/spec/background_queue/server_lib/worker_thread_spec.rb +2 -2
  34. data/spec/background_queue/utils_spec.rb +30 -0
  35. data/spec/background_queue/worker/calling_spec.rb +3 -1
  36. data/spec/background_queue/worker/environment_spec.rb +3 -1
  37. data/spec/background_queue/worker/logger_spec.rb +58 -0
  38. data/spec/background_queue/worker/progress_spec.rb +82 -0
  39. data/spec/background_queue/worker/worker_loader_spec.rb +1 -1
  40. data/spec/resources/summary_worker.rb +18 -0
  41. data/spec/shared/queue_registry_shared.rb +4 -3
  42. data/spec/support/simple_task.rb +24 -0
  43. 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
@@ -3,3 +3,5 @@ require "background_queue/worker/environment"
3
3
  require "background_queue/worker/worker_loader"
4
4
  require "background_queue/worker/calling"
5
5
  require "background_queue/worker/config"
6
+ require "background_queue/worker/progress"
7
+ require "background_queue/worker/logger"
@@ -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
- TCPSocket.should_receive(:open).with(:host, :port) { :socket }
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, {}, {} ).should eq([true, :server])
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
- context "extracting the environment entry" do
61
- it "gets_the_current environment from env" do
62
- ENV.should_receive(:has_key?).with("RAILS_ENV") { true }
63
- ENV.should_receive(:[]).with("RAILS_ENV") { :the_env }
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 "gets_the_current environment from Rails" do
68
- ENV.should_receive(:has_key?).with("RAILS_ENV") { false }
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
- context "with development environment" do
74
- before do
75
- BackgroundQueue::Config.stub(:current_environment) { 'development' }
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::Config.stub(:current_environment) { 'development' }
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(1)
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
- ss.stop
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