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.
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