background_queue 0.2.0

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