background_queue 0.2.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 (91) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +48 -0
  4. data/Gemfile +19 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +69 -0
  7. data/Rakefile +42 -0
  8. data/TODO +2 -0
  9. data/VERSION +1 -0
  10. data/background_queue.gemspec +158 -0
  11. data/bin/bg_queue +26 -0
  12. data/lib/background_queue.rb +8 -0
  13. data/lib/background_queue/client.rb +96 -0
  14. data/lib/background_queue/client_lib/command.rb +36 -0
  15. data/lib/background_queue/client_lib/config.rb +109 -0
  16. data/lib/background_queue/client_lib/connection.rb +105 -0
  17. data/lib/background_queue/client_lib/job_handle.rb +19 -0
  18. data/lib/background_queue/command.rb +49 -0
  19. data/lib/background_queue/config.rb +118 -0
  20. data/lib/background_queue/server_lib/balanced_queue.rb +108 -0
  21. data/lib/background_queue/server_lib/config.rb +339 -0
  22. data/lib/background_queue/server_lib/event_connection.rb +133 -0
  23. data/lib/background_queue/server_lib/event_server.rb +35 -0
  24. data/lib/background_queue/server_lib/job.rb +252 -0
  25. data/lib/background_queue/server_lib/job_registry.rb +30 -0
  26. data/lib/background_queue/server_lib/lru.rb +193 -0
  27. data/lib/background_queue/server_lib/owner.rb +54 -0
  28. data/lib/background_queue/server_lib/priority_queue.rb +156 -0
  29. data/lib/background_queue/server_lib/queue_registry.rb +123 -0
  30. data/lib/background_queue/server_lib/server.rb +314 -0
  31. data/lib/background_queue/server_lib/sorted_workers.rb +52 -0
  32. data/lib/background_queue/server_lib/task.rb +79 -0
  33. data/lib/background_queue/server_lib/task_registry.rb +51 -0
  34. data/lib/background_queue/server_lib/thread_manager.rb +121 -0
  35. data/lib/background_queue/server_lib/worker.rb +18 -0
  36. data/lib/background_queue/server_lib/worker_balancer.rb +97 -0
  37. data/lib/background_queue/server_lib/worker_client.rb +94 -0
  38. data/lib/background_queue/server_lib/worker_thread.rb +70 -0
  39. data/lib/background_queue/utils.rb +40 -0
  40. data/lib/background_queue/worker/base.rb +46 -0
  41. data/lib/background_queue/worker/calling.rb +59 -0
  42. data/lib/background_queue/worker/config.rb +35 -0
  43. data/lib/background_queue/worker/environment.rb +70 -0
  44. data/lib/background_queue/worker/worker_loader.rb +94 -0
  45. data/lib/background_queue_server.rb +21 -0
  46. data/lib/background_queue_worker.rb +5 -0
  47. data/spec/background_queue/client_lib/command_spec.rb +75 -0
  48. data/spec/background_queue/client_lib/config_spec.rb +156 -0
  49. data/spec/background_queue/client_lib/connection_spec.rb +170 -0
  50. data/spec/background_queue/client_spec.rb +95 -0
  51. data/spec/background_queue/command_spec.rb +34 -0
  52. data/spec/background_queue/config_spec.rb +134 -0
  53. data/spec/background_queue/server_lib/balanced_queue_spec.rb +122 -0
  54. data/spec/background_queue/server_lib/config_spec.rb +443 -0
  55. data/spec/background_queue/server_lib/event_connection_spec.rb +190 -0
  56. data/spec/background_queue/server_lib/event_server_spec.rb +48 -0
  57. data/spec/background_queue/server_lib/integration/full_test_spec.rb +247 -0
  58. data/spec/background_queue/server_lib/integration/queue_integration_spec.rb +98 -0
  59. data/spec/background_queue/server_lib/integration/serialize_spec.rb +127 -0
  60. data/spec/background_queue/server_lib/job_registry_spec.rb +65 -0
  61. data/spec/background_queue/server_lib/job_spec.rb +525 -0
  62. data/spec/background_queue/server_lib/owner_spec.rb +33 -0
  63. data/spec/background_queue/server_lib/priority_queue_spec.rb +182 -0
  64. data/spec/background_queue/server_lib/server_spec.rb +353 -0
  65. data/spec/background_queue/server_lib/sorted_workers_spec.rb +122 -0
  66. data/spec/background_queue/server_lib/task_registry_spec.rb +69 -0
  67. data/spec/background_queue/server_lib/task_spec.rb +20 -0
  68. data/spec/background_queue/server_lib/thread_manager_spec.rb +106 -0
  69. data/spec/background_queue/server_lib/worker_balancer_spec.rb +127 -0
  70. data/spec/background_queue/server_lib/worker_client_spec.rb +196 -0
  71. data/spec/background_queue/server_lib/worker_thread_spec.rb +125 -0
  72. data/spec/background_queue/utils_spec.rb +27 -0
  73. data/spec/background_queue/worker/base_spec.rb +35 -0
  74. data/spec/background_queue/worker/calling_spec.rb +103 -0
  75. data/spec/background_queue/worker/environment_spec.rb +67 -0
  76. data/spec/background_queue/worker/worker_loader_spec.rb +103 -0
  77. data/spec/background_queue_spec.rb +7 -0
  78. data/spec/resources/config-client.yml +7 -0
  79. data/spec/resources/config-serialize.yml +12 -0
  80. data/spec/resources/config.yml +12 -0
  81. data/spec/resources/example_worker.rb +4 -0
  82. data/spec/resources/example_worker_with_error.rb +4 -0
  83. data/spec/resources/test_worker.rb +8 -0
  84. data/spec/shared/queue_registry_shared.rb +216 -0
  85. data/spec/spec_helper.rb +15 -0
  86. data/spec/support/default_task.rb +9 -0
  87. data/spec/support/private.rb +23 -0
  88. data/spec/support/simple_server.rb +28 -0
  89. data/spec/support/simple_task.rb +58 -0
  90. data/spec/support/test_worker_server.rb +205 -0
  91. metadata +254 -0
@@ -0,0 +1,190 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue_server'
3
+
4
+
5
+ describe BackgroundQueue::ServerLib::EventConnection do
6
+
7
+ subject {
8
+ s = BackgroundQueue::ServerLib::EventConnection.new(:something)
9
+ s.server = SimpleServer.new
10
+ s.post_init
11
+ s
12
+ }
13
+
14
+
15
+ let(:data) { [1, 20, "12345678901234567890"].pack("SLZ20")}
16
+
17
+ context "#receive_data" do
18
+ it "can handle a packet in 1 call" do
19
+ subject.should_receive(:process_data).with("12345678901234567890")
20
+ subject.receive_data(data)
21
+ end
22
+
23
+ it "can handle the header in 2 calls" do
24
+ subject.should_receive(:process_data).with("12345678901234567890")
25
+ subject.receive_data(data.slice!(0, 2))
26
+ subject.receive_data(data.slice!(0, 4))
27
+ subject.receive_data(data)
28
+ end
29
+
30
+ it "can handle the body in 2 calls" do
31
+ subject.should_receive(:process_data).with("12345678901234567890")
32
+ subject.receive_data(data.slice!(0, 6))
33
+ subject.receive_data(data.slice!(0, 4))
34
+ subject.receive_data(data)
35
+ end
36
+
37
+ it "can handle the packets crossing header/body boundry" do
38
+ subject.should_receive(:process_data).with("12345678901234567890")
39
+ subject.receive_data(data.slice!(0, 4))
40
+ subject.receive_data(data.slice!(0, 10))
41
+ subject.receive_data(data)
42
+ end
43
+
44
+ it "will error if the version is wrong" do
45
+ expect { subject.receive_data("ABCDEFG") }.to raise_exception("Invalid header version: 16961")
46
+ end
47
+ end
48
+
49
+ context "#process_data" do
50
+ it "will convert the data to a json object" do
51
+ BackgroundQueue::Command.should_receive(:from_buf).with("{'a':'b'}").and_return(:command)
52
+ subject.should_receive(:process_command).with(:command).and_return(:result)
53
+ subject.should_receive(:send_result).with(:result)
54
+ subject.process_data("{'a':'b'}")
55
+ end
56
+
57
+ it "will return an error if the json is invalid" do
58
+ subject.should_receive(:send_error)
59
+ subject.process_data("{sdf, sdfsdf}")
60
+ end
61
+
62
+ end
63
+
64
+ context "#process_command" do
65
+ it "will call process_add_task_cmd if cmd is add_task" do
66
+ cmd = double("command", :code=>'add_task')
67
+ subject.should_receive(:process_add_task_command).with(cmd).and_return(:result)
68
+ subject.process_command(cmd).should eq(:result)
69
+ end
70
+
71
+ it "will call process_add_tasks_command if cmd is add_tasks" do
72
+ cmd = double("command", :code=>'add_tasks')
73
+ subject.should_receive(:process_add_tasks_command).with(cmd).and_return(:result)
74
+ subject.process_command(cmd).should eq(:result)
75
+ end
76
+
77
+ it "will call process_remove_tasks_command if cmd is remove_tasks" do
78
+ cmd = double("command", :code=>'remove_tasks')
79
+ subject.should_receive(:process_remove_tasks_command).with(cmd).and_return(:result)
80
+ subject.process_command(cmd).should eq(:result)
81
+ end
82
+
83
+ it "will call process_get_status_command if cmd is get_status" do
84
+ cmd = double("command", :code=>'get_status')
85
+ subject.should_receive(:process_get_status_command).with(cmd).and_return(:result)
86
+ subject.process_command(cmd).should eq(:result)
87
+ end
88
+
89
+ it "will raise an error if unknown task" do
90
+ cmd = double("command", :code=>'dunno')
91
+ expect { subject.process_command(cmd).should eq(:result) }.to raise_exception('Unknown command: "dunno"')
92
+ end
93
+ end
94
+
95
+ context "#send_result" do
96
+ it "will serialize the result to a json string and send" do
97
+ cmd = BackgroundQueue::Command.new('a', {}, {})
98
+ subject.should_receive(:send).with(cmd.to_buf)
99
+ subject.send_result(cmd)
100
+ end
101
+ end
102
+
103
+ context "#send_error" do
104
+ it "will wrap the error into a command and call send_result" do
105
+ BackgroundQueue::Command.should_receive(:new).with(:error, {}, {:message=>"error"}).and_return(:command)
106
+ subject.should_receive(:send_result).with(:command)
107
+ subject.send_error("error")
108
+ end
109
+ end
110
+
111
+ context "#send" do
112
+ it "will add a header to the data and call send_data" do
113
+ data = [1,4,"data"].pack("SLZ4")
114
+ subject.should_receive(:send_data).with(data)
115
+ subject.send("data")
116
+ end
117
+ end
118
+
119
+ context "#process_add_task_command" do
120
+ it "builds a task from the command and adds it to the queue" do
121
+
122
+ server = SimpleServer.new(:task_queue=>double('task_queue'))
123
+ server.task_queue.should_receive(:add_task).with(:task)
124
+
125
+ command = BackgroundQueue::Command.new(:add_task, {}, {'owner_id'=>:owner_id, :job_id=>:job_id, 'task_id'=>:task_id, :priority=>:priority, :params=>:params, :worker=>:worker } )
126
+
127
+ BackgroundQueue::ServerLib::Task.should_receive(:new).with(:owner_id, :job_id, :task_id, :priority, :worker, :params, command.options).and_return(:task)
128
+
129
+
130
+ subject.server = server
131
+ subject.process_add_task_command(command).code.should eq(:result)
132
+ end
133
+
134
+ end
135
+
136
+
137
+ context "#process_add_tasks_command" do
138
+ it "builds a set of tasks from the command and adds them to the queue" do
139
+
140
+ server = SimpleServer.new(:task_queue=>double('task_queue'))
141
+ server.task_queue.should_receive(:add_task).with(:task1)
142
+ server.task_queue.should_receive(:add_task).with(:task2)
143
+
144
+ command = BackgroundQueue::Command.new(:add_tasks, {}, {'owner_id'=>:owner_id, :job_id=>:job_id, :tasks=>[[:task1_id, {:a=>:b}], [:task2_id, {:e=>:f}]], :priority=>:priority, :params=>:params, :worker=>:worker, :shared_parameters=>{:shared=>:params} } )
145
+
146
+ BackgroundQueue::ServerLib::Task.should_receive(:new).with(:owner_id, :job_id, :task1_id, :priority, :worker, {:a=>:b, :shared=>:params}, command.options).and_return(:task1)
147
+ BackgroundQueue::ServerLib::Task.should_receive(:new).with(:owner_id, :job_id, :task2_id, :priority, :worker, {:e=>:f, :shared=>:params}, command.options).and_return(:task2)
148
+
149
+ subject.server = server
150
+ subject.process_add_tasks_command(command).code.should eq(:result)
151
+ end
152
+
153
+ end
154
+
155
+ context "#process_get_status_command" do
156
+ it "will get the status of a registered job" do
157
+ server = SimpleServer.new(:jobs=>double('jobs'))
158
+ job = double("job")
159
+ server.jobs.should_receive(:get_job).with(:job_id).and_return(job)
160
+ job.should_receive(:get_current_progress).and_return({:percent=>100, :caption=>"done"})
161
+ subject.server = server
162
+
163
+ command = BackgroundQueue::Command.new(:get_status, {}, {:job_id=>:job_id } )
164
+
165
+ result = subject.process_get_status_command(command)
166
+
167
+ result.args[:percent].should eq(100)
168
+ result.args[:caption].should eq("done")
169
+ result.code.should eq(:status)
170
+ end
171
+
172
+ it "will return job_not_found if job is not registered" do
173
+ server = SimpleServer.new(:jobs=>double('jobs'))
174
+ job = double("job")
175
+ subject.server = server
176
+ server.jobs.should_receive(:get_job).with(:job_id).and_return(nil)
177
+ command = BackgroundQueue::Command.new(:get_status, {}, {:job_id=>:job_id } )
178
+
179
+ result = subject.process_get_status_command(command)
180
+
181
+ result.code.should eq(:job_not_found)
182
+
183
+ end
184
+ end
185
+
186
+
187
+
188
+
189
+
190
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue_server'
3
+
4
+ #module Rufus
5
+ # module Scheduler
6
+ # class EmScheduler
7
+ # end
8
+ # end
9
+ #end
10
+
11
+ describe BackgroundQueue::ServerLib::EventServer do
12
+
13
+ let(:server) { SimpleServer.new(:config=>double("config", :address=>double("address", :host=>:host, :port=>:port))) }
14
+ subject { BackgroundQueue::ServerLib::EventServer.new(server) }
15
+
16
+
17
+ context "#start" do
18
+ it "starts the event machine" do
19
+
20
+ con=double("conection")
21
+ con.should_receive("server=".intern).with(server)
22
+ EventMachine.should_receive(:run).and_yield
23
+ EventMachine.should_receive(:start_server).with(:host, :port, BackgroundQueue::ServerLib::EventConnection).and_yield(con)
24
+
25
+ job = double("job")
26
+ scheduler = double("scheduler")
27
+ scheduler.should_receive(:start)
28
+ server.config.stub(:jobs=>[job])
29
+ Rufus::Scheduler::EmScheduler.should_receive(:new).and_return(scheduler)
30
+ job.should_receive(:schedule).with(scheduler, server)
31
+
32
+ subject.start
33
+ end
34
+ end
35
+
36
+ # context "#start_jobs" do
37
+ # it "schedules jobs" do
38
+ # job = double("job")
39
+ # server.config.stub(:jobs=>[job])
40
+ # Rufus::Scheduler::EmScheduler.should_receive(:start_new).and_return(:scheduler)
41
+ # job.should_receive(:schedule).with(:scheduler, server)
42
+ # EventMachine.should_receive(:run).and_yield
43
+ # subject.start_jobs
44
+ # end
45
+ # end
46
+
47
+
48
+ end
@@ -0,0 +1,247 @@
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 "Full Test" do
19
+
20
+ context "simple task" do
21
+
22
+ it "will call worker server" 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
+
36
+ begin
37
+
38
+ meth_name = nil
39
+ ss = TestWorkerServer.new(8001)
40
+ ss.start(Proc.new { |controller|
41
+ meth_name = controller.request.request_method
42
+ controller.render :text => lambda { |response,output|
43
+ output.write({:percent=>100, :caption=>"Done"}.to_json)
44
+ }, :type=>"text/text"
45
+ #controller.render :text=>, :type=>"text/text"
46
+ })
47
+
48
+
49
+ client_config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-client.yml')
50
+
51
+ client = BackgroundQueue::Client.new(client_config_path)
52
+
53
+
54
+ job_handle = client.add_task(:some_worker, :owner_id, :job_id, :task_id, 2, {:something=>:else}, {:domain=>"www.example.com"} )
55
+
56
+
57
+ ss.wait_to_be_called.should be_true
58
+
59
+ result = client.get_status(job_handle)
60
+
61
+ result.code.should eq(:status)
62
+ result.args[:percent].should eq(100)
63
+ result.args[:caption].should eq('Done')
64
+
65
+ meth_name.should eq("POST")
66
+ ss.stop
67
+ ensure
68
+ server.stop
69
+
70
+ thread.join
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ context "init task" do
77
+ it "will spawn more tasks" do
78
+ config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config.yml')
79
+
80
+
81
+
82
+ server = BackgroundQueue::ServerLib::Server.new
83
+
84
+
85
+
86
+ thread = Thread.new {
87
+ server.start(:config=>config_path, :skip_pid=>true, :command=>:run, :log_file=>"/tmp/bq.log", :log_level=>'debug')
88
+ }
89
+
90
+
91
+
92
+ while server.event_server.nil? || !server.event_server.running
93
+ sleep(0.1)
94
+ end
95
+
96
+ begin
97
+
98
+ task_pos = 0
99
+
100
+
101
+
102
+ client_config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-client.yml')
103
+
104
+ client = BackgroundQueue::Client.new(client_config_path)
105
+
106
+ meth_name = nil
107
+ ss = TestWorkerServer.new(8001, true)
108
+ ss.start(Proc.new { |controller|
109
+ #puts "worker called"
110
+ meth_name = controller.request.request_method
111
+ if task_pos == 0
112
+ task_pos += 1
113
+ #puts "Adding more tasks"
114
+ client2 = BackgroundQueue::Client.new(client_config_path)
115
+ result2, server_used2 = client.add_tasks(:some_worker, :owner_id, :job_id, [[:task1_id, {:a=>:b}], [:task2_id, {:e=>:f}]], 2, {:something=>:else}, {:domain=>"www.example.com"} )
116
+ end
117
+ controller.render :text=>{:percent=>100, :caption=>"Done"}.to_json, :type=>"text/text"
118
+ })
119
+
120
+
121
+
122
+ job_handle = client.add_task(:some_worker, :owner_id, :job_id, :task_id, 2, {:something=>:else}, {:domain=>"www.example.com", :weight=>20.0, :exclude=>true, :initial_progress_caption=>"Loading" } )
123
+
124
+ result = client.get_status(job_handle )
125
+
126
+ #puts "test1"
127
+ result.code.should eq(:status)
128
+ result.args[:percent].should eq(0.0)
129
+ result.args[:caption].should eq('Loading')
130
+
131
+
132
+ stats = client.get_stats(job_handle.server)
133
+ stats[:running].should eq(1)
134
+
135
+
136
+
137
+ ss.allow_to_be_called
138
+
139
+ ss.wait_to_be_called.should be_true
140
+
141
+
142
+ result = client.get_status(job_handle )
143
+
144
+ #puts "test1"
145
+ result.code.should eq(:status)
146
+ result.args[:percent].should eq(20.0)
147
+ result.args[:caption].should eq('Done')
148
+
149
+ meth_name.should eq("POST")
150
+
151
+ stats = client.get_stats(job_handle.server)
152
+ stats[:running].should eq(1)
153
+ stats[:run_tasks].should eq(1)
154
+
155
+ #pp server
156
+
157
+ ss.allow_to_be_called
158
+ ss.wait_to_be_called.should be_true
159
+
160
+ result = client.get_status(job_handle )
161
+
162
+ #puts "test2"
163
+ result.code.should eq(:status)
164
+ result.args[:percent].should eq(60.0)
165
+ result.args[:caption].should eq('Done (2/2)')
166
+
167
+
168
+ ss.allow_to_be_called
169
+ ss.wait_to_be_called.should be_true
170
+
171
+ result = client.get_status(job_handle )
172
+
173
+ #puts "test3"
174
+ result.code.should eq(:status)
175
+ result.args[:percent].should eq(100.0)
176
+ result.args[:caption].should eq('Done (2/2)')
177
+
178
+ stats = client.get_stats(job_handle.server)
179
+ stats[:tasks].should eq(0)
180
+ stats[:running].should eq(0)
181
+ stats[:run_tasks].should eq(3)
182
+
183
+ ss.stop
184
+ ensure
185
+ server.stop
186
+ thread.join
187
+ end
188
+ end
189
+ end
190
+
191
+
192
+ context "with worker" do
193
+
194
+ it "will load a worker and call it" do
195
+
196
+ config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config.yml')
197
+ BackgroundQueue::Worker::Config.worker_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/')
198
+ BackgroundQueue::Worker::Config.secret = "this_is_used_to_make_sure_it_is_secure"
199
+
200
+ server = BackgroundQueue::ServerLib::Server.new
201
+
202
+ thread = Thread.new {
203
+ server.start(:config=>config_path, :skip_pid=>true, :command=>:run, :log_file=>"/tmp/bq.log", :log_level=>'debug')
204
+ }
205
+
206
+ while server.event_server.nil? || !server.event_server.running
207
+ sleep(0.1)
208
+ end
209
+
210
+ begin
211
+
212
+ meth_name = nil
213
+ ss = TestWorkerServer.new(8001)
214
+ ss.start(Proc.new { |controller|
215
+ #puts controller.params.inspect
216
+ controller.class.send(:include, BackgroundQueue::Worker::Calling)
217
+ # puts "B"
218
+ controller.run_worker
219
+ # puts "C"
220
+ })
221
+
222
+
223
+ client_config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-client.yml')
224
+
225
+ client = BackgroundQueue::Client.new(client_config_path)
226
+
227
+
228
+ job_handle = client.add_task(:test_worker, :owner_id, :job_id, :task_id, 2, {:something=>:else}, {:domain=>"www.example.com"} )
229
+
230
+ ss.wait_to_be_called.should be_true
231
+
232
+ result = client.get_status(job_handle)
233
+
234
+ result.code.should eq(:status)
235
+ result.args[:percent].should eq(100)
236
+ result.args[:caption].should eq('Done')
237
+
238
+ ss.stop
239
+ ensure
240
+ server.stop
241
+
242
+ thread.join
243
+ end
244
+ end
245
+
246
+ end
247
+ end