background_queue 0.2.0 → 0.3.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.
- 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:
|