background_queue 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/VERSION +1 -1
- data/background_queue.gemspec +10 -3
- data/lib/background_queue/server_lib/error_task_list.rb +116 -0
- data/lib/background_queue/server_lib/event_connection.rb +1 -0
- data/lib/background_queue/server_lib/job.rb +5 -0
- data/lib/background_queue/server_lib/server.rb +9 -1
- data/lib/background_queue/server_lib/task.rb +14 -0
- data/lib/background_queue/server_lib/thread_manager.rb +10 -0
- data/lib/background_queue/server_lib/worker_client.rb +13 -3
- data/lib/background_queue/server_lib/worker_thread.rb +12 -10
- data/lib/background_queue/worker/config.rb +2 -0
- data/lib/background_queue_server.rb +2 -0
- data/spec/background_queue/server_lib/error_task_list_spec.rb +142 -0
- data/spec/background_queue/server_lib/integration/queue_integration_spec.rb +25 -1
- data/spec/background_queue/server_lib/worker_client_spec.rb +61 -58
- data/spec/background_queue/server_lib/worker_thread_spec.rb +26 -16
- data/spec/spec_helper.rb +1 -1
- data/spec/support/simple_server.rb +2 -0
- metadata +47 -24
- data/spec/background_queue_spec.rb +0 -7
data/Gemfile
CHANGED
@@ -6,6 +6,8 @@ gem "json"
|
|
6
6
|
gem "rufus-scheduler"
|
7
7
|
gem "eventmachine", "~>0.12.10"
|
8
8
|
gem "ipaddress", "~> 0.8.0"
|
9
|
+
gem "ipaddress", "~> 0.8.0"
|
10
|
+
gem "algorithms", "~> 0.5.0"
|
9
11
|
|
10
12
|
# Add dependencies to develop your gem here.
|
11
13
|
# Include everything needed to run rake, tests, features, etc.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/background_queue.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "background_queue"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["MarkPent"]
|
12
|
-
s.date = "2012-10-
|
12
|
+
s.date = "2012-10-17"
|
13
13
|
s.description = "Organise background tasks so they will not overload the machine(s) running the tasks, while still giving a fair, balanced allocation of running time to members in the queue"
|
14
14
|
s.email = "mark.pent@gmail.com"
|
15
15
|
s.executables = ["bg_queue"]
|
@@ -40,6 +40,7 @@ Gem::Specification.new do |s|
|
|
40
40
|
"lib/background_queue/config.rb",
|
41
41
|
"lib/background_queue/server_lib/balanced_queue.rb",
|
42
42
|
"lib/background_queue/server_lib/config.rb",
|
43
|
+
"lib/background_queue/server_lib/error_task_list.rb",
|
43
44
|
"lib/background_queue/server_lib/event_connection.rb",
|
44
45
|
"lib/background_queue/server_lib/event_server.rb",
|
45
46
|
"lib/background_queue/server_lib/job.rb",
|
@@ -73,6 +74,7 @@ Gem::Specification.new do |s|
|
|
73
74
|
"spec/background_queue/config_spec.rb",
|
74
75
|
"spec/background_queue/server_lib/balanced_queue_spec.rb",
|
75
76
|
"spec/background_queue/server_lib/config_spec.rb",
|
77
|
+
"spec/background_queue/server_lib/error_task_list_spec.rb",
|
76
78
|
"spec/background_queue/server_lib/event_connection_spec.rb",
|
77
79
|
"spec/background_queue/server_lib/event_server_spec.rb",
|
78
80
|
"spec/background_queue/server_lib/integration/full_test_spec.rb",
|
@@ -95,7 +97,6 @@ Gem::Specification.new do |s|
|
|
95
97
|
"spec/background_queue/worker/calling_spec.rb",
|
96
98
|
"spec/background_queue/worker/environment_spec.rb",
|
97
99
|
"spec/background_queue/worker/worker_loader_spec.rb",
|
98
|
-
"spec/background_queue_spec.rb",
|
99
100
|
"spec/resources/config-client.yml",
|
100
101
|
"spec/resources/config-serialize.yml",
|
101
102
|
"spec/resources/config.yml",
|
@@ -124,6 +125,8 @@ Gem::Specification.new do |s|
|
|
124
125
|
s.add_runtime_dependency(%q<rufus-scheduler>, [">= 0"])
|
125
126
|
s.add_runtime_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
126
127
|
s.add_runtime_dependency(%q<ipaddress>, ["~> 0.8.0"])
|
128
|
+
s.add_runtime_dependency(%q<ipaddress>, ["~> 0.8.0"])
|
129
|
+
s.add_runtime_dependency(%q<algorithms>, ["~> 0.5.0"])
|
127
130
|
s.add_development_dependency(%q<rspec>, [">= 2.9.0"])
|
128
131
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
129
132
|
s.add_development_dependency(%q<yard>, ["~> 0.7"])
|
@@ -135,6 +138,8 @@ Gem::Specification.new do |s|
|
|
135
138
|
s.add_dependency(%q<rufus-scheduler>, [">= 0"])
|
136
139
|
s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
137
140
|
s.add_dependency(%q<ipaddress>, ["~> 0.8.0"])
|
141
|
+
s.add_dependency(%q<ipaddress>, ["~> 0.8.0"])
|
142
|
+
s.add_dependency(%q<algorithms>, ["~> 0.5.0"])
|
138
143
|
s.add_dependency(%q<rspec>, [">= 2.9.0"])
|
139
144
|
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
140
145
|
s.add_dependency(%q<yard>, ["~> 0.7"])
|
@@ -147,6 +152,8 @@ Gem::Specification.new do |s|
|
|
147
152
|
s.add_dependency(%q<rufus-scheduler>, [">= 0"])
|
148
153
|
s.add_dependency(%q<eventmachine>, ["~> 0.12.10"])
|
149
154
|
s.add_dependency(%q<ipaddress>, ["~> 0.8.0"])
|
155
|
+
s.add_dependency(%q<ipaddress>, ["~> 0.8.0"])
|
156
|
+
s.add_dependency(%q<algorithms>, ["~> 0.5.0"])
|
150
157
|
s.add_dependency(%q<rspec>, [">= 2.9.0"])
|
151
158
|
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
152
159
|
s.add_dependency(%q<yard>, ["~> 0.7"])
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'algorithms'
|
2
|
+
module BackgroundQueue::ServerLib
|
3
|
+
|
4
|
+
class ErrorTaskList
|
5
|
+
|
6
|
+
attr_reader :tasks
|
7
|
+
attr_reader :task_count
|
8
|
+
|
9
|
+
def initialize(server)
|
10
|
+
@server = server
|
11
|
+
@tasks = Containers::RBTreeMap.new
|
12
|
+
@mutex = Mutex.new
|
13
|
+
@current_next_at = nil
|
14
|
+
@current_runner = nil
|
15
|
+
@task_count = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_task(task)
|
19
|
+
task.increment_error_count
|
20
|
+
delay = calculate_delay(task.get_error_count)
|
21
|
+
add_item(task, Time.now.to_i + delay)
|
22
|
+
end
|
23
|
+
|
24
|
+
def calculate_delay(error_count)
|
25
|
+
delay = error_count * error_count
|
26
|
+
delay > 120 ? 120 : delay
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_item(task, time_at)
|
30
|
+
@mutex.synchronize {
|
31
|
+
existing = @tasks[time_at]
|
32
|
+
if existing.nil?
|
33
|
+
existing = []
|
34
|
+
@tasks[time_at] = existing
|
35
|
+
end
|
36
|
+
existing << task
|
37
|
+
@task_count += 1
|
38
|
+
queue_next_event(time_at)
|
39
|
+
}
|
40
|
+
@server.logger.debug("Task #{task.id} queued to retry in #{time_at - Time.now.to_f} seconds")
|
41
|
+
end
|
42
|
+
|
43
|
+
def queue_next_event(time_at)
|
44
|
+
if @current_next_at.nil? || @current_next_at > time_at
|
45
|
+
@current_runner.cancel if @current_runner
|
46
|
+
@current_next_at = time_at
|
47
|
+
@current_runner = BackgroundQueue::ServerLib::ErrorTaskList::RunAt.new(time_at) {
|
48
|
+
self.next_event
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def next_event
|
54
|
+
@mutex.synchronize {
|
55
|
+
@current_runner = nil
|
56
|
+
@current_next_at = nil
|
57
|
+
while @tasks.size > 0 && @tasks.min_key < (Time.now.to_f + 0.1)
|
58
|
+
next_tasks = @tasks.delete_min
|
59
|
+
for task in next_tasks
|
60
|
+
@server.task_queue.finish_task(task)
|
61
|
+
@server.task_queue.add_task(task)
|
62
|
+
@task_count -= 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
queue_next_event(@tasks.min_key) if @tasks.size > 0
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def flush
|
70
|
+
@server.logger.debug("Flushing #{@tasks.size} tasks from error list")
|
71
|
+
@current_runner.cancel if @current_runner
|
72
|
+
@current_runner = nil
|
73
|
+
@mutex.synchronize {
|
74
|
+
while @tasks.size > 0
|
75
|
+
next_tasks = @tasks.delete_min
|
76
|
+
for task in next_tasks
|
77
|
+
@server.task_queue.finish_task(task)
|
78
|
+
@server.task_queue.add_task(task)
|
79
|
+
@task_count -= 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def wait_for_event
|
86
|
+
runner = @current_runner
|
87
|
+
runner.wait_for_run if runner
|
88
|
+
end
|
89
|
+
|
90
|
+
class RunAt
|
91
|
+
#i dont care about thread safety: it doesnt matter if an event runs twice.
|
92
|
+
def initialize(at, &block)
|
93
|
+
@running = true
|
94
|
+
@th = Thread.new {
|
95
|
+
delay = at - Time.now.to_f
|
96
|
+
sleep(delay)
|
97
|
+
if @running
|
98
|
+
block.call
|
99
|
+
@running = false
|
100
|
+
end
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def cancel
|
105
|
+
return false if !@running
|
106
|
+
@running = false
|
107
|
+
@th.run #wake the sleep up
|
108
|
+
end
|
109
|
+
|
110
|
+
def wait_for_run
|
111
|
+
@th.join
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module BackgroundQueue::ServerLib
|
2
2
|
class Job < PriorityQueue
|
3
3
|
|
4
|
+
|
4
5
|
attr_accessor :id
|
5
6
|
attr_reader :running_status
|
6
7
|
attr_reader :running_ordered_status
|
@@ -79,6 +80,10 @@ module BackgroundQueue::ServerLib
|
|
79
80
|
pop
|
80
81
|
end
|
81
82
|
|
83
|
+
def remove_item(item)
|
84
|
+
remove(item)
|
85
|
+
end
|
86
|
+
|
82
87
|
def finish_item(item)
|
83
88
|
@synchronous_count-=1 if item.synchronous?
|
84
89
|
end
|
@@ -7,6 +7,7 @@ module BackgroundQueue::ServerLib
|
|
7
7
|
attr_accessor :config
|
8
8
|
attr_accessor :thread_manager
|
9
9
|
attr_accessor :task_queue
|
10
|
+
attr_accessor :error_tasks
|
10
11
|
attr_accessor :event_server
|
11
12
|
attr_accessor :workers
|
12
13
|
attr_accessor :jobs
|
@@ -37,7 +38,7 @@ module BackgroundQueue::ServerLib
|
|
37
38
|
OptionParser.new do |opts|
|
38
39
|
opts.banner = "Usage: server command [options]"
|
39
40
|
case options[:command]
|
40
|
-
when :start, :test
|
41
|
+
when :start, :test, :run
|
41
42
|
opts.on("-c", "--config PATH", "Configuration Path") do |cp|
|
42
43
|
options[:config] = cp
|
43
44
|
end
|
@@ -60,6 +61,10 @@ module BackgroundQueue::ServerLib
|
|
60
61
|
opts.on("-e", "--environment [RAILS_ENV]", "testing/development/production (development)") do |env|
|
61
62
|
env_to_load = env
|
62
63
|
end
|
64
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
65
|
+
puts opts
|
66
|
+
exit
|
67
|
+
end
|
63
68
|
end.parse!(argv)
|
64
69
|
|
65
70
|
ENV['RAILS_ENV']=env_to_load
|
@@ -254,6 +259,8 @@ module BackgroundQueue::ServerLib
|
|
254
259
|
|
255
260
|
@event_server = BackgroundQueue::ServerLib::EventServer.new(self)
|
256
261
|
|
262
|
+
@error_tasks = BackgroundQueue::ServerLib::ErrorTaskList.new(self)
|
263
|
+
|
257
264
|
@jobs = BackgroundQueue::ServerLib::JobRegistry.new
|
258
265
|
|
259
266
|
load_tasks(config.task_file)
|
@@ -265,6 +272,7 @@ module BackgroundQueue::ServerLib
|
|
265
272
|
@running = false
|
266
273
|
@event_server.stop
|
267
274
|
@thread_manager.wait(timeout_secs)
|
275
|
+
@error_tasks.flush
|
268
276
|
save_tasks(config.task_file)
|
269
277
|
end
|
270
278
|
|
@@ -68,6 +68,20 @@ module BackgroundQueue::ServerLib
|
|
68
68
|
@options[:initial_progress_caption]
|
69
69
|
end
|
70
70
|
|
71
|
+
def get_error_count
|
72
|
+
if @error_count.nil?
|
73
|
+
0
|
74
|
+
else
|
75
|
+
@error_count
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def increment_error_count
|
81
|
+
@error_count = get_error_count + 1
|
82
|
+
end
|
83
|
+
|
84
|
+
|
71
85
|
def set_worker_status(status)
|
72
86
|
raise "Task without job set" if @job.nil?
|
73
87
|
status[:task_id] = self.id
|
@@ -111,6 +111,16 @@ class BackgroundQueue::ServerLib::ThreadManager
|
|
111
111
|
#ignore
|
112
112
|
end
|
113
113
|
end
|
114
|
+
|
115
|
+
begin
|
116
|
+
Timeout::timeout(timeout_limit) {
|
117
|
+
for thread in @threads
|
118
|
+
thread.join
|
119
|
+
end
|
120
|
+
}
|
121
|
+
rescue Timeout::Error => te2
|
122
|
+
@server.logger.error("Timeout while waiting for forced stop threads to finish")
|
123
|
+
end
|
114
124
|
end
|
115
125
|
end
|
116
126
|
|
@@ -19,11 +19,17 @@ module BackgroundQueue::ServerLib
|
|
19
19
|
read_response(worker, response, task)
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
return :ok
|
23
|
+
rescue BackgroundQueue::ServerLib::WorkerError => we
|
24
|
+
@server.logger.error("Worker Error sending request #{task.id} to worker: #{e.message}")
|
25
|
+
return :worker_error
|
26
|
+
rescue BackgroundQueue::ServerLib::ThreadManager::ForcedStop => fe
|
27
|
+
@server.logger.error("Thread stop while sending request #{task.id} to worker: #{fe.message}")
|
28
|
+
return :stop
|
23
29
|
rescue Exception=>e
|
24
30
|
@server.logger.error("Error sending request #{task.id} to worker: #{e.message}")
|
25
31
|
@server.logger.debug(e.backtrace.join("\n"))
|
26
|
-
return
|
32
|
+
return :fatal_error
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
@@ -49,7 +55,7 @@ module BackgroundQueue::ServerLib
|
|
49
55
|
@prev_chunk = nil
|
50
56
|
end
|
51
57
|
else
|
52
|
-
raise "Invalid response code (#{http_response.code}) when calling #{worker.uri.to_s}"
|
58
|
+
raise BackgroundQueue::ServerLib::WorkerError, "Invalid response code (#{http_response.code}) when calling #{worker.uri.to_s}"
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
@@ -91,4 +97,8 @@ module BackgroundQueue::ServerLib
|
|
91
97
|
end
|
92
98
|
|
93
99
|
end
|
100
|
+
|
101
|
+
class WorkerError < Exception
|
102
|
+
|
103
|
+
end
|
94
104
|
end
|
@@ -31,24 +31,26 @@ module BackgroundQueue::ServerLib
|
|
31
31
|
Kernel.sleep(1) unless !@server.running?
|
32
32
|
else
|
33
33
|
client = build_client
|
34
|
-
|
34
|
+
result = client.send_request(worker, task, @server.config.secret)
|
35
|
+
if result == :ok
|
35
36
|
@server.logger.debug("called worker for task #{task.id}")
|
36
37
|
@server.workers.finish_using_worker(worker, true)
|
37
38
|
@server.task_queue.finish_task(task)
|
38
39
|
@server.change_stat(:running, -1)
|
39
40
|
@server.change_stat(:run_tasks, 1)
|
40
|
-
|
41
41
|
return true
|
42
42
|
else
|
43
43
|
@server.logger.debug("failed calling worker for task #{task.id}")
|
44
|
-
@server.workers.finish_using_worker(worker,
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
@server.workers.finish_using_worker(worker, result == :worker_error)
|
45
|
+
@server.error_tasks.add_task(task)
|
46
|
+
return result != :stop
|
47
|
+
#error_count += 1
|
48
|
+
#if error_count > 5
|
49
|
+
# @server.logger.debug("error count exceeded for task #{task.id}, returning to queue")
|
50
|
+
# @server.task_queue.finish_task(task)
|
51
|
+
# @server.task_queue.add_task(task)
|
52
|
+
# return true
|
53
|
+
#end
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "background_queue/utils"
|
2
2
|
require "background_queue/config"
|
3
|
+
require "background_queue/command"
|
3
4
|
require "background_queue/server_lib/lru"
|
4
5
|
require "background_queue/server_lib/config"
|
5
6
|
require "background_queue/server_lib/priority_queue"
|
@@ -19,3 +20,4 @@ require "background_queue/server_lib/worker_thread"
|
|
19
20
|
require "background_queue/server_lib/server"
|
20
21
|
require "background_queue/server_lib/event_server"
|
21
22
|
require "background_queue/server_lib/event_connection"
|
23
|
+
require "background_queue/server_lib/error_task_list"
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
require 'background_queue_server'
|
3
|
+
|
4
|
+
|
5
|
+
describe BackgroundQueue::ServerLib::ErrorTaskList do
|
6
|
+
|
7
|
+
let(:server) {
|
8
|
+
SimpleServer.new
|
9
|
+
}
|
10
|
+
|
11
|
+
subject {
|
12
|
+
BackgroundQueue::ServerLib::ErrorTaskList.new(server)
|
13
|
+
}
|
14
|
+
|
15
|
+
let(:task) {
|
16
|
+
double("task", :get_error_count=>1, :id=>:task1)
|
17
|
+
}
|
18
|
+
let(:task2) {
|
19
|
+
double("task2", :get_error_count=>1, :id=>:task2)
|
20
|
+
}
|
21
|
+
let(:task3) {
|
22
|
+
double("task3", :get_error_count=>1, :id=>:task3)
|
23
|
+
}
|
24
|
+
let(:task4) {
|
25
|
+
double("task4", :get_error_count=>1, :id=>:task4)
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
context "#add_task" do
|
30
|
+
it "will calculate the delay then add it to the list using it" do
|
31
|
+
subject.should_receive(:calculate_delay).with(1).and_return(1)
|
32
|
+
subject.should_receive(:add_item).with(task, 101)
|
33
|
+
Time.any_instance.should_receive(:to_i).and_return(100)
|
34
|
+
task.should_receive(:increment_error_count)
|
35
|
+
subject.add_task(task)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "#calculate_delay" do
|
40
|
+
it "will square the error count" do
|
41
|
+
subject.calculate_delay(1).should eq(1)
|
42
|
+
subject.calculate_delay(2).should eq(4)
|
43
|
+
subject.calculate_delay(3).should eq(9)
|
44
|
+
subject.calculate_delay(10).should eq(100)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "will use a threshold (120)" do
|
48
|
+
subject.calculate_delay(50).should eq(120)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "#add_item" do
|
53
|
+
it "will add an item using the scheduled time as key" do
|
54
|
+
subject.should_receive(:queue_next_event).with(10)
|
55
|
+
subject.add_item(task, 10)
|
56
|
+
subject.tasks.size.should eq(1)
|
57
|
+
subject.tasks.min_key.should be(10)
|
58
|
+
subject.tasks.delete_min.should eq([task])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "will add the task to an event at the same time" do
|
62
|
+
subject.should_receive(:queue_next_event).twice.with(10)
|
63
|
+
subject.should_receive(:queue_next_event).with(20)
|
64
|
+
subject.add_item(task, 10)
|
65
|
+
subject.add_item(task2, 10)
|
66
|
+
subject.add_item(task3, 20)
|
67
|
+
subject.tasks.size.should eq(2)
|
68
|
+
subject.tasks.min_key.should be(10)
|
69
|
+
subject.tasks.delete_min.should eq([task, task2])
|
70
|
+
subject.tasks.min_key.should be(20)
|
71
|
+
subject.tasks.delete_min.should eq([task3])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "#queue_next_event" do
|
76
|
+
it "will queue a new time if its closer then the last" do
|
77
|
+
timer = double("timer")
|
78
|
+
timer.should_receive(:cancel)
|
79
|
+
BackgroundQueue::ServerLib::ErrorTaskList::RunAt.should_receive(:new).with(10).and_return(timer)
|
80
|
+
BackgroundQueue::ServerLib::ErrorTaskList::RunAt.should_receive(:new).with(5).and_return(timer)
|
81
|
+
subject.queue_next_event(10)
|
82
|
+
subject.queue_next_event(5)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "will not queue a new event if its furhter away" do
|
86
|
+
timer = double("timer")
|
87
|
+
BackgroundQueue::ServerLib::ErrorTaskList::RunAt.should_receive(:new).with(10).and_return(timer)
|
88
|
+
subject.queue_next_event(10)
|
89
|
+
subject.queue_next_event(20)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "will fire an event" do
|
93
|
+
subject.should_receive(:next_event)
|
94
|
+
subject.queue_next_event(Time.now.to_f + 0.1)
|
95
|
+
subject.wait_for_event
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "#next_event" do
|
100
|
+
it "will get all the tasks before the current time and re-add them" do
|
101
|
+
subject.tasks[Time.now.to_f] = [task, task2]
|
102
|
+
subject.tasks[Time.now.to_f + 0.01] = [task3]
|
103
|
+
task_at = Time.now.to_f + 1.0
|
104
|
+
subject.tasks[task_at] = [task4]
|
105
|
+
server.task_queue = double("tq")
|
106
|
+
server.task_queue.should_receive(:finish_task).with(task)
|
107
|
+
server.task_queue.should_receive(:add_task).with(task)
|
108
|
+
server.task_queue.should_receive(:finish_task).with(task2)
|
109
|
+
server.task_queue.should_receive(:add_task).with(task2)
|
110
|
+
server.task_queue.should_receive(:finish_task).with(task3)
|
111
|
+
server.task_queue.should_receive(:add_task).with(task3)
|
112
|
+
subject.should_receive(:queue_next_event).with(task_at)
|
113
|
+
subject.next_event
|
114
|
+
subject.tasks.size.should eq(1)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "RunAt" do
|
119
|
+
it "will run a task at the specificied time" do
|
120
|
+
run_at = Time.now.to_f + 0.1
|
121
|
+
when_run = 0
|
122
|
+
runner = BackgroundQueue::ServerLib::ErrorTaskList::RunAt.new(run_at) {
|
123
|
+
when_run = Time.now.to_f
|
124
|
+
}
|
125
|
+
runner.wait_for_run
|
126
|
+
when_run.should_not eq(0)
|
127
|
+
when_run.to_i.should eq(run_at.to_i)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "can be cancelled" do
|
131
|
+
run_at = Time.now.to_f + 0.5
|
132
|
+
has_run = false
|
133
|
+
runner = BackgroundQueue::ServerLib::ErrorTaskList::RunAt.new(run_at) {
|
134
|
+
has_run = true
|
135
|
+
}
|
136
|
+
sleep(0.05)
|
137
|
+
runner.cancel.should be_true
|
138
|
+
runner.wait_for_run
|
139
|
+
has_run.should be_false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -72,7 +72,7 @@ describe "Queue Integration" do
|
|
72
72
|
|
73
73
|
task = subject.next_item
|
74
74
|
task.id.should be(:task_id)
|
75
|
-
subject.next_item.should be_nil
|
75
|
+
subject.next_item.should be_nil
|
76
76
|
subject.finish_item(task)
|
77
77
|
subject.next_item.id.should eq(:task_id2)
|
78
78
|
|
@@ -94,5 +94,29 @@ describe "Queue Integration" do
|
|
94
94
|
|
95
95
|
end
|
96
96
|
end
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
context "Duplicate Tasks" do
|
101
|
+
it "will replace a duplicate task not running" do
|
102
|
+
subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3, {:synchronous=>true}))
|
103
|
+
subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3, {:synchronous=>true}))
|
104
|
+
task = subject.next_item
|
105
|
+
task.id.should be(:task_id)
|
106
|
+
subject.next_item.should be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
it "will queue a duplicate task that is running" do
|
110
|
+
subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3, {:synchronous=>true}))
|
111
|
+
task = subject.next_item
|
112
|
+
task.id.should be(:task_id)
|
113
|
+
subject.next_item.should be_nil
|
114
|
+
subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3, {:synchronous=>true}))
|
115
|
+
subject.next_item.should be_nil
|
116
|
+
subject.finish_item(task)
|
117
|
+
task = subject.next_item
|
118
|
+
task.id.should be(:task_id)
|
119
|
+
end
|
120
|
+
end
|
97
121
|
|
98
122
|
end
|
@@ -40,7 +40,7 @@ describe BackgroundQueue::ServerLib::WorkerClient do
|
|
40
40
|
task = SimpleTask.new(:owner_id, :job_id, :task_id, 3, { :domain=>"www.example.com" })
|
41
41
|
subject.should_receive(:build_request).with(uri, task, "auth").and_return(:post_request)
|
42
42
|
Net::HTTP.should_receive(:start).with("127.0.0.1", 3000).and_raise("connection error")
|
43
|
-
subject.send_request(worker_config, task, "auth").should
|
43
|
+
subject.send_request(worker_config, task, "auth").should eq(:fatal_error)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -112,7 +112,7 @@ describe BackgroundQueue::ServerLib::WorkerClient do
|
|
112
112
|
|
113
113
|
context "can handle thread cancelling" do
|
114
114
|
#this can cause issues with other tests....
|
115
|
-
|
115
|
+
it "will return false if server stopped", :can_be_flakey=>true do
|
116
116
|
|
117
117
|
mutex = Mutex.new
|
118
118
|
resource = ConditionVariable.new
|
@@ -122,66 +122,69 @@ describe BackgroundQueue::ServerLib::WorkerClient do
|
|
122
122
|
|
123
123
|
run_request = false
|
124
124
|
ss = TestWorkerServer.new(8001)
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
125
|
+
begin
|
126
|
+
ss.start(Proc.new { |controller|
|
127
|
+
#puts "in proc"
|
128
|
+
|
129
|
+
mutex2.synchronize {
|
130
|
+
resource2.signal
|
131
|
+
}
|
132
|
+
#puts "in proc: waiting"
|
133
|
+
mutex.synchronize {
|
134
|
+
resource.wait(mutex)
|
135
|
+
}
|
136
|
+
#puts "waited"
|
137
|
+
run_request = true
|
138
|
+
controller.render :text =>{:percent=>100, :caption=>"Done"}.to_json, :type=>"text/text"
|
139
|
+
})
|
140
|
+
|
141
|
+
|
142
|
+
uri = URI("http://127.0.0.1:8001/background_queue")
|
143
|
+
worker_config = BackgroundQueue::ServerLib::Worker.new(uri)
|
144
|
+
task = SimpleTask.new(:owner_id, :job_id, :task_id, 3, { :domain=>"www.example.com" })
|
145
|
+
|
146
|
+
call_result = nil
|
147
|
+
t1 = Thread.new {
|
148
|
+
#puts "calling"
|
149
|
+
begin
|
150
|
+
status = Timeout::timeout(2) {
|
151
|
+
call_result = subject.send_request(worker_config, task, "abcd")
|
152
|
+
# puts "called"
|
153
|
+
}
|
154
|
+
rescue Timeout::Error=>te
|
155
|
+
#puts "timeout"
|
156
|
+
call_result = :timeout
|
157
|
+
end
|
158
|
+
mutex2.synchronize {
|
159
|
+
resource2.signal
|
160
|
+
}
|
130
161
|
}
|
131
|
-
|
132
|
-
|
133
|
-
|
162
|
+
|
163
|
+
#wait until we know the request has been sent and is processing
|
164
|
+
mutex2.synchronize {
|
165
|
+
resource2.wait(mutex2)
|
134
166
|
}
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
uri = URI("http://127.0.0.1:8001/background_queue")
|
142
|
-
worker_config = BackgroundQueue::ServerLib::Worker.new(uri)
|
143
|
-
task = SimpleTask.new(:owner_id, :job_id, :task_id, 3, { :domain=>"www.example.com" })
|
144
|
-
|
145
|
-
call_result = nil
|
146
|
-
t1 = Thread.new {
|
147
|
-
#puts "calling"
|
148
|
-
begin
|
149
|
-
status = Timeout::timeout(2) {
|
150
|
-
call_result = subject.send_request(worker_config, task, "abcd")
|
151
|
-
# puts "called"
|
152
|
-
}
|
153
|
-
rescue Timeout::Error=>te
|
154
|
-
#puts "timeout"
|
155
|
-
call_result = :timeout
|
156
|
-
end
|
167
|
+
run_request.should be_false
|
168
|
+
#puts "cancelling"
|
169
|
+
t1.raise BackgroundQueue::ServerLib::ThreadManager::ForcedStop.new("Timeout when forcing threads to stop")
|
170
|
+
|
171
|
+
#puts "canceled"
|
172
|
+
#wait until we know the request has been cancelled
|
157
173
|
mutex2.synchronize {
|
158
|
-
resource2.
|
174
|
+
resource2.wait(mutex2)
|
159
175
|
}
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
mutex2.synchronize {
|
173
|
-
resource2.wait(mutex2)
|
174
|
-
}
|
175
|
-
call_result.should be_false
|
176
|
-
run_request.should be_false
|
177
|
-
|
178
|
-
mutex.synchronize {
|
179
|
-
resource.signal
|
180
|
-
}
|
181
|
-
|
182
|
-
|
183
|
-
t1.join
|
184
|
-
ss.stop
|
176
|
+
call_result.should eq(:stop)
|
177
|
+
run_request.should be_false
|
178
|
+
|
179
|
+
mutex.synchronize {
|
180
|
+
resource.signal
|
181
|
+
}
|
182
|
+
|
183
|
+
|
184
|
+
t1.join
|
185
|
+
ensure
|
186
|
+
ss.stop
|
187
|
+
end
|
185
188
|
|
186
189
|
end
|
187
190
|
|
@@ -11,9 +11,12 @@ describe BackgroundQueue::ServerLib::WorkerThread do
|
|
11
11
|
let(:workers) {
|
12
12
|
double("workers")
|
13
13
|
}
|
14
|
+
let(:error_tasks) {
|
15
|
+
double("error_tasks")
|
16
|
+
}
|
14
17
|
|
15
18
|
let(:server) {
|
16
|
-
SimpleServer.new(:task_queue=>balanced_queue, :workers=>workers, :config=>double("conf", :secret=>:secret))
|
19
|
+
SimpleServer.new(:task_queue=>balanced_queue, :workers=>workers, :config=>double("conf", :secret=>:secret), :error_tasks=>error_tasks)
|
17
20
|
}
|
18
21
|
|
19
22
|
subject { BackgroundQueue::ServerLib::WorkerThread.new(server) }
|
@@ -48,31 +51,38 @@ describe BackgroundQueue::ServerLib::WorkerThread do
|
|
48
51
|
server.stub('running?'=>true)
|
49
52
|
worker = double("worker")
|
50
53
|
task = DefaultTask.new
|
51
|
-
|
54
|
+
worker_client = double("worker_client")
|
55
|
+
subject.should_receive(:build_client).and_return(worker_client)
|
56
|
+
worker_client.should_receive(:send_request).with(worker, task, :secret).and_return(:ok)
|
52
57
|
server.workers.should_receive(:get_next_worker).and_return(worker)
|
53
58
|
server.workers.should_receive(:finish_using_worker).with(worker, true)
|
54
59
|
server.task_queue.should_receive(:finish_task).with(task)
|
55
60
|
subject.call_worker(task).should be_true
|
56
61
|
end
|
57
62
|
|
58
|
-
it "will
|
63
|
+
it "will regegister as a failed worker if send_request returns :fatal_error" do
|
59
64
|
server.stub('running?'=>true)
|
60
65
|
worker = double("worker")
|
61
66
|
task = DefaultTask.new
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
subject.should_receive(:build_client).twice {
|
69
|
-
count += 1
|
70
|
-
count == 1 ? worker_client1 : worker_client2
|
71
|
-
}
|
72
|
-
server.workers.should_receive(:get_next_worker).twice.and_return(worker)
|
67
|
+
server.error_tasks.should_receive(:add_task).with(task)
|
68
|
+
worker_client = double("worker_client")
|
69
|
+
subject.should_receive(:build_client).and_return(worker_client)
|
70
|
+
worker_client.should_receive(:send_request).with(worker, task, :secret).and_return(:fatal_error)
|
71
|
+
server.workers.should_receive(:get_next_worker).and_return(worker)
|
73
72
|
server.workers.should_receive(:finish_using_worker).with(worker, false)
|
73
|
+
subject.call_worker(task).should be_true
|
74
|
+
end
|
75
|
+
|
76
|
+
it "will regegister as a ok worker if send_request returns :worker_error" do
|
77
|
+
server.stub('running?'=>true)
|
78
|
+
worker = double("worker")
|
79
|
+
task = DefaultTask.new
|
80
|
+
server.error_tasks.should_receive(:add_task).with(task)
|
81
|
+
worker_client = double("worker_client")
|
82
|
+
subject.should_receive(:build_client).and_return(worker_client)
|
83
|
+
worker_client.should_receive(:send_request).with(worker, task, :secret).and_return(:worker_error)
|
84
|
+
server.workers.should_receive(:get_next_worker).and_return(worker)
|
74
85
|
server.workers.should_receive(:finish_using_worker).with(worker, true)
|
75
|
-
server.task_queue.should_receive(:finish_task).with(task)
|
76
86
|
subject.call_worker(task).should be_true
|
77
87
|
end
|
78
88
|
|
@@ -86,7 +96,7 @@ describe BackgroundQueue::ServerLib::WorkerThread do
|
|
86
96
|
count == 1 ? nil : worker
|
87
97
|
}
|
88
98
|
Kernel.should_receive(:sleep).with(1)
|
89
|
-
BackgroundQueue::ServerLib::WorkerClient.any_instance.should_receive(:send_request).with(worker, task, :secret).and_return(
|
99
|
+
BackgroundQueue::ServerLib::WorkerClient.any_instance.should_receive(:send_request).with(worker, task, :secret).and_return(:ok)
|
90
100
|
server.workers.should_receive(:finish_using_worker).with(worker, true)
|
91
101
|
server.task_queue.should_receive(:finish_task).with(task)
|
92
102
|
subject.call_worker(task).should be_true
|
data/spec/spec_helper.rb
CHANGED
@@ -6,6 +6,7 @@ class SimpleServer
|
|
6
6
|
attr_accessor :workers
|
7
7
|
attr_accessor :jobs
|
8
8
|
attr_accessor :logger
|
9
|
+
attr_accessor :error_tasks
|
9
10
|
|
10
11
|
def initialize(options={})
|
11
12
|
@logger = Logger.new("/dev/null")
|
@@ -15,6 +16,7 @@ class SimpleServer
|
|
15
16
|
@event_server = options[:event_server]
|
16
17
|
@workers = options[:workers]
|
17
18
|
@jobs = options[:jobs]
|
19
|
+
@error_tasks = options[:error_tasks]
|
18
20
|
end
|
19
21
|
|
20
22
|
def running?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: background_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
16
|
-
requirement: &
|
16
|
+
requirement: &19238880 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *19238880
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rufus-scheduler
|
27
|
-
requirement: &
|
27
|
+
requirement: &20184220 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *20184220
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: eventmachine
|
38
|
-
requirement: &
|
38
|
+
requirement: &20182860 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 0.12.10
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *20182860
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: ipaddress
|
49
|
-
requirement: &
|
49
|
+
requirement: &20180600 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,32 @@ dependencies:
|
|
54
54
|
version: 0.8.0
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *20180600
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: ipaddress
|
60
|
+
requirement: &20178440 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.8.0
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *20178440
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: algorithms
|
71
|
+
requirement: &20177140 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.5.0
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *20177140
|
58
80
|
- !ruby/object:Gem::Dependency
|
59
81
|
name: rspec
|
60
|
-
requirement: &
|
82
|
+
requirement: &19623560 !ruby/object:Gem::Requirement
|
61
83
|
none: false
|
62
84
|
requirements:
|
63
85
|
- - ! '>='
|
@@ -65,10 +87,10 @@ dependencies:
|
|
65
87
|
version: 2.9.0
|
66
88
|
type: :development
|
67
89
|
prerelease: false
|
68
|
-
version_requirements: *
|
90
|
+
version_requirements: *19623560
|
69
91
|
- !ruby/object:Gem::Dependency
|
70
92
|
name: jeweler
|
71
|
-
requirement: &
|
93
|
+
requirement: &19621540 !ruby/object:Gem::Requirement
|
72
94
|
none: false
|
73
95
|
requirements:
|
74
96
|
- - ~>
|
@@ -76,10 +98,10 @@ dependencies:
|
|
76
98
|
version: 1.8.3
|
77
99
|
type: :development
|
78
100
|
prerelease: false
|
79
|
-
version_requirements: *
|
101
|
+
version_requirements: *19621540
|
80
102
|
- !ruby/object:Gem::Dependency
|
81
103
|
name: yard
|
82
|
-
requirement: &
|
104
|
+
requirement: &19617840 !ruby/object:Gem::Requirement
|
83
105
|
none: false
|
84
106
|
requirements:
|
85
107
|
- - ~>
|
@@ -87,10 +109,10 @@ dependencies:
|
|
87
109
|
version: '0.7'
|
88
110
|
type: :development
|
89
111
|
prerelease: false
|
90
|
-
version_requirements: *
|
112
|
+
version_requirements: *19617840
|
91
113
|
- !ruby/object:Gem::Dependency
|
92
114
|
name: rdoc
|
93
|
-
requirement: &
|
115
|
+
requirement: &19615920 !ruby/object:Gem::Requirement
|
94
116
|
none: false
|
95
117
|
requirements:
|
96
118
|
- - ~>
|
@@ -98,10 +120,10 @@ dependencies:
|
|
98
120
|
version: '3.12'
|
99
121
|
type: :development
|
100
122
|
prerelease: false
|
101
|
-
version_requirements: *
|
123
|
+
version_requirements: *19615920
|
102
124
|
- !ruby/object:Gem::Dependency
|
103
125
|
name: bundler
|
104
|
-
requirement: &
|
126
|
+
requirement: &20601320 !ruby/object:Gem::Requirement
|
105
127
|
none: false
|
106
128
|
requirements:
|
107
129
|
- - ~>
|
@@ -109,10 +131,10 @@ dependencies:
|
|
109
131
|
version: 1.0.0
|
110
132
|
type: :development
|
111
133
|
prerelease: false
|
112
|
-
version_requirements: *
|
134
|
+
version_requirements: *20601320
|
113
135
|
- !ruby/object:Gem::Dependency
|
114
136
|
name: redcarpet
|
115
|
-
requirement: &
|
137
|
+
requirement: &20599700 !ruby/object:Gem::Requirement
|
116
138
|
none: false
|
117
139
|
requirements:
|
118
140
|
- - ~>
|
@@ -120,7 +142,7 @@ dependencies:
|
|
120
142
|
version: 2.1.1
|
121
143
|
type: :development
|
122
144
|
prerelease: false
|
123
|
-
version_requirements: *
|
145
|
+
version_requirements: *20599700
|
124
146
|
description: Organise background tasks so they will not overload the machine(s) running
|
125
147
|
the tasks, while still giving a fair, balanced allocation of running time to members
|
126
148
|
in the queue
|
@@ -154,6 +176,7 @@ files:
|
|
154
176
|
- lib/background_queue/config.rb
|
155
177
|
- lib/background_queue/server_lib/balanced_queue.rb
|
156
178
|
- lib/background_queue/server_lib/config.rb
|
179
|
+
- lib/background_queue/server_lib/error_task_list.rb
|
157
180
|
- lib/background_queue/server_lib/event_connection.rb
|
158
181
|
- lib/background_queue/server_lib/event_server.rb
|
159
182
|
- lib/background_queue/server_lib/job.rb
|
@@ -187,6 +210,7 @@ files:
|
|
187
210
|
- spec/background_queue/config_spec.rb
|
188
211
|
- spec/background_queue/server_lib/balanced_queue_spec.rb
|
189
212
|
- spec/background_queue/server_lib/config_spec.rb
|
213
|
+
- spec/background_queue/server_lib/error_task_list_spec.rb
|
190
214
|
- spec/background_queue/server_lib/event_connection_spec.rb
|
191
215
|
- spec/background_queue/server_lib/event_server_spec.rb
|
192
216
|
- spec/background_queue/server_lib/integration/full_test_spec.rb
|
@@ -209,7 +233,6 @@ files:
|
|
209
233
|
- spec/background_queue/worker/calling_spec.rb
|
210
234
|
- spec/background_queue/worker/environment_spec.rb
|
211
235
|
- spec/background_queue/worker/worker_loader_spec.rb
|
212
|
-
- spec/background_queue_spec.rb
|
213
236
|
- spec/resources/config-client.yml
|
214
237
|
- spec/resources/config-serialize.yml
|
215
238
|
- spec/resources/config.yml
|
@@ -238,7 +261,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
261
|
version: '0'
|
239
262
|
segments:
|
240
263
|
- 0
|
241
|
-
hash:
|
264
|
+
hash: 613144620285186166
|
242
265
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
266
|
none: false
|
244
267
|
requirements:
|