resque-director 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +76 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/lib/resque/plugins/director/config.rb +39 -0
- data/lib/resque/plugins/director/lifecycle.rb +30 -0
- data/lib/resque/plugins/director/scaler.rb +72 -0
- data/lib/resque/plugins/director/worker_tracker.rb +57 -0
- data/lib/resque/plugins/director.rb +95 -0
- data/lib/resque-director.rb +7 -0
- data/resque-director.gemspec +76 -0
- data/spec/redis-test.conf +417 -0
- data/spec/resque/plugins/director/config_spec.rb +37 -0
- data/spec/resque/plugins/director/lifecycle_spec.rb +20 -0
- data/spec/resque/plugins/director/scaler_spec.rb +246 -0
- data/spec/resque/plugins/director/worker_tracker_spec.rb +137 -0
- data/spec/resque/plugins/director_spec.rb +200 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/test_job.rb +7 -0
- metadata +176 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Nolan Frausto
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
= Resque Director
|
2
|
+
|
3
|
+
Resque Director is a plugin for the Resque queueing system (http://github.com/defunkt/resque) that "directs" workers on a queue by automatically adding or removing workers from a queue based on how backed up a queue becomes, or how long it takes for a job to get pulled off the queue.
|
4
|
+
|
5
|
+
==About
|
6
|
+
|
7
|
+
resque-director is mainly useful for when you are managing a large number of workers and don't want to waste resources keeping all of them waiting when they are not being used. Also useful in queues where the influx of jobs can change dramatically from time to time: enabling more workers during the times when the queue is filling up more quickly, and less in the opposite scenario. Different queues can be given different directions as well.
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
When creating your jobs you should include (make sure to include not extend) Resque::Plugins::Director and add direction options.
|
12
|
+
|
13
|
+
For Example:
|
14
|
+
|
15
|
+
class Job
|
16
|
+
include Resque::Plugins::Director
|
17
|
+
direct :min_workers => 2, :max_workers => 4, :max_time => 60, :max_queue => 10, :wait_time => 30
|
18
|
+
@queue = :test
|
19
|
+
|
20
|
+
#rest of your Job class here
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
=== Configuration Options
|
25
|
+
|
26
|
+
<b>min_workers</b>:: specifies the minimum number of workers running at any point in time. If there are no workers running or less than the minimum running it will start as many workers necessary to get it to the minimum. The default is 1.
|
27
|
+
|
28
|
+
<b>max_workers</b>:: specifies the maximum number of workers running at any point in time. It will never start more than the maximum number of workers. If anything less than or equal to zero is specified as the maximum it will be treated as if there is no maximum, and theoretically an infinite number of workers could be added. The default is 0.
|
29
|
+
|
30
|
+
<b>max_time</b>:: the maximum time in seconds that a job takes to get pulled off the queue, if a job takes longer than this time then a worker is added. If anything less than or equal to zero is specified as the maximum time, this field will be ignored. The default is 0.
|
31
|
+
|
32
|
+
<b>max_queue</b>:: the maximum jobs that can build up in a queue, if more than this number of jobs build up then a worker is added. If anything less than or equal to zero is specified as the maximum queue, this field will be ignored. The default is 0.
|
33
|
+
|
34
|
+
<b>wait_time</b>:: the time that it will wait after adding or removing a worker before being allowed to add or remove workers again. The default is 60 seconds.
|
35
|
+
|
36
|
+
== Worker Options
|
37
|
+
|
38
|
+
<b>start_override</b>:: This will run exactly what you put in the command override as a system command to start A SINGLE worker, allowing you to customize the starting of a worker fully. The system command "QUEUE=queue_name rake resque:work" is run by default, where queue_name is whatever queue the job is running.
|
39
|
+
|
40
|
+
<b>stop_override</b>:: This will run exactly what you put in the command override as a system command to stop A SINGLE worker, allowing you to customize the stoping of a worker fully. Process.kill("QUIT", worker_pid) is used to stop the worker by default, where worker_pid is the PID of a worker.
|
41
|
+
|
42
|
+
=== Starting/Stopping Workers Example
|
43
|
+
|
44
|
+
class Job
|
45
|
+
include Resque::Plugins::Director
|
46
|
+
direct :start_override => "./start_command_to_run", :stop_override => "./stop_command_to_run"
|
47
|
+
@queue = :test
|
48
|
+
|
49
|
+
#rest of your Job class here
|
50
|
+
end
|
51
|
+
|
52
|
+
=== Conditions For Removing Workers
|
53
|
+
|
54
|
+
A worker will be removed if the jobs in the queue fall below half of the <b>max_queue</b>, or if the time it takes for a job to be pulled off of a queue falls below half of the <b>max_time</b>. Workers will be scaled down to the minimum if there are no jobs on the queue.
|
55
|
+
|
56
|
+
=== Special Cases
|
57
|
+
|
58
|
+
* If a max_worker is less than min_worker then the default for max_worker will be used (there will be no maximum).
|
59
|
+
* If a min_workers is set to anything less than 1 then it will be treated as 0.
|
60
|
+
|
61
|
+
|
62
|
+
== Contributing to resque-reconnect
|
63
|
+
|
64
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
65
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
66
|
+
* Fork the project
|
67
|
+
* Start a feature/bugfix branch
|
68
|
+
* Commit and push until you are happy with your contribution
|
69
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
70
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
71
|
+
|
72
|
+
== Copyright
|
73
|
+
|
74
|
+
Copyright (c) 2011 Nolan Frausto. See LICENSE.txt for
|
75
|
+
further details.
|
76
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$LOAD_PATH.unshift 'lib'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
require 'resque/tasks'
|
7
|
+
|
8
|
+
begin
|
9
|
+
Bundler.setup(:default, :development)
|
10
|
+
rescue Bundler::BundlerError => e
|
11
|
+
$stderr.puts e.message
|
12
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
13
|
+
exit e.status_code
|
14
|
+
end
|
15
|
+
require 'rake'
|
16
|
+
|
17
|
+
require 'jeweler'
|
18
|
+
Jeweler::Tasks.new do |gem|
|
19
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
20
|
+
gem.name = "resque-director"
|
21
|
+
gem.homepage = "http://github.com/frausto/resque-director"
|
22
|
+
gem.license = "MIT"
|
23
|
+
gem.summary = %Q{resque plugin for dynamically adding/removing workers to a queue}
|
24
|
+
gem.description = %Q{resque plugin for dynamically adding/removing workers to a queue}
|
25
|
+
gem.email = "nrfrausto@gmail.com"
|
26
|
+
gem.authors = ["Nolan Frausto"]
|
27
|
+
# dependencies defined in Gemfile
|
28
|
+
end
|
29
|
+
Jeweler::RubygemsDotOrgTasks.new
|
30
|
+
|
31
|
+
require 'rspec/core'
|
32
|
+
require 'rspec/core/rake_task'
|
33
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
34
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
35
|
+
end
|
36
|
+
|
37
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
38
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
39
|
+
spec.rcov = true
|
40
|
+
end
|
41
|
+
|
42
|
+
task :default => :spec
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "resque-director #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
module Director
|
4
|
+
module Config
|
5
|
+
extend self
|
6
|
+
|
7
|
+
attr_accessor :queue
|
8
|
+
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
:min_workers => 1,
|
11
|
+
:max_workers => 0,
|
12
|
+
:max_time => 0,
|
13
|
+
:max_queue => 0,
|
14
|
+
:wait_time => 60,
|
15
|
+
:start_override => nil,
|
16
|
+
:stop_override => nil
|
17
|
+
}
|
18
|
+
|
19
|
+
def reset!
|
20
|
+
DEFAULT_OPTIONS.each do |key, default|
|
21
|
+
attr_reader key
|
22
|
+
self.instance_variable_set("@#{key.to_s}", default)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def setup(options={})
|
27
|
+
DEFAULT_OPTIONS.each do |key, value|
|
28
|
+
self.instance_variable_set("@#{key.to_s}", options[key] || value)
|
29
|
+
end
|
30
|
+
|
31
|
+
@min_workers = 0 if @min_workers < 0
|
32
|
+
@max_workers = DEFAULT_OPTIONS[:max_workers] if @max_workers < @min_workers
|
33
|
+
end
|
34
|
+
|
35
|
+
reset!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
module Director
|
4
|
+
module Lifecycle
|
5
|
+
|
6
|
+
def self.included(base) #:nodoc:
|
7
|
+
base.class_eval do
|
8
|
+
alias_method :push_without_lifecycle, :push
|
9
|
+
extend ClassMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
def push(queue, item)
|
16
|
+
if item.respond_to?(:[]=)
|
17
|
+
timestamp = {'resdirecttime' => Time.now.utc.to_i}
|
18
|
+
item[:args] = item[:args].push(timestamp)
|
19
|
+
end
|
20
|
+
push_without_lifecycle queue, item
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Resque
|
29
|
+
include Resque::Plugins::Director::Lifecycle
|
30
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
module Director
|
4
|
+
class Scaler
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def scale_up(number_of_workers=1)
|
8
|
+
number_of_workers = WorkerTracker.new.total_to_add(number_of_workers)
|
9
|
+
scaling(number_of_workers) do
|
10
|
+
number_of_workers.times { start }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def scale_down(number_of_workers=1)
|
15
|
+
tracker = WorkerTracker.new
|
16
|
+
number_of_workers = tracker.total_to_remove(number_of_workers)
|
17
|
+
|
18
|
+
scaling(number_of_workers) do
|
19
|
+
stop(tracker, number_of_workers)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def scale_down_to_minimum
|
24
|
+
tracker = WorkerTracker.new
|
25
|
+
number_of_workers = tracker.total_to_go_to_minimum
|
26
|
+
stop(tracker, number_of_workers)
|
27
|
+
end
|
28
|
+
|
29
|
+
def scale_within_requirements
|
30
|
+
number_of_workers = WorkerTracker.new.total_for_requirements
|
31
|
+
|
32
|
+
if number_of_workers > 0
|
33
|
+
scale_up(number_of_workers)
|
34
|
+
elsif number_of_workers < 0
|
35
|
+
scale_down(number_of_workers * -1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def scaling(number_of_workers=1)
|
40
|
+
return unless time_to_scale? && number_of_workers > 0
|
41
|
+
yield
|
42
|
+
Resque.redis.set("last_scaled_#{Config.queue}", Time.now.utc.to_i)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def time_to_scale?
|
48
|
+
last_time = Resque.redis.get("last_scaled_#{Config.queue}")
|
49
|
+
return true if last_time.nil?
|
50
|
+
time_passed = (Time.now.utc - Time.at(last_time.to_i).utc)
|
51
|
+
time_passed >= Config.wait_time
|
52
|
+
end
|
53
|
+
|
54
|
+
def start
|
55
|
+
default_command = "QUEUE=#{Config.queue} rake resque:work &"
|
56
|
+
system(Config.start_override || default_command)
|
57
|
+
end
|
58
|
+
|
59
|
+
def stop(tracker, number_of_workers)
|
60
|
+
if Config.stop_override
|
61
|
+
number_of_workers.times { system(Config.stop_override) }
|
62
|
+
else
|
63
|
+
valid_workers = tracker.workers.select{|w| w.hostname == `hostname`.chomp}
|
64
|
+
worker_pids = valid_workers[0...number_of_workers].map(&:pid)
|
65
|
+
worker_pids.each {|pid| Process.kill("QUIT", pid)}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
module Director
|
4
|
+
class WorkerTracker
|
5
|
+
attr_reader :workers
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@workers = current_workers
|
9
|
+
@number_working = @workers.size
|
10
|
+
end
|
11
|
+
|
12
|
+
def total_for_requirements
|
13
|
+
start_number = workers_to_start
|
14
|
+
stop_number = workers_to_stop
|
15
|
+
return start_number if start_number > 0
|
16
|
+
return stop_number if stop_number < 0
|
17
|
+
0
|
18
|
+
end
|
19
|
+
|
20
|
+
def total_to_go_to_minimum
|
21
|
+
to_minimum = @number_working - Config.min_workers
|
22
|
+
to_minimum > 0 ? to_minimum : 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def total_to_add(number_to_start)
|
26
|
+
return number_to_start if Config.max_workers <= 0
|
27
|
+
scale_limit = Config.max_workers - @number_working
|
28
|
+
number_to_start > scale_limit ? scale_limit : number_to_start
|
29
|
+
end
|
30
|
+
|
31
|
+
def total_to_remove(number_to_stop)
|
32
|
+
min_workers = Config.min_workers <= 0 ? 1 : Config.min_workers
|
33
|
+
scale_limit = @number_working - min_workers
|
34
|
+
number_to_stop > scale_limit ? scale_limit : number_to_stop
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def workers_to_start
|
40
|
+
min_workers = Config.min_workers <= 0 ? 1 : Config.min_workers
|
41
|
+
workers_to_start = min_workers - @number_working
|
42
|
+
end
|
43
|
+
|
44
|
+
def workers_to_stop
|
45
|
+
return 0 if Config.max_workers <= 0
|
46
|
+
workers_to_stop = Config.max_workers - @number_working
|
47
|
+
end
|
48
|
+
|
49
|
+
def current_workers
|
50
|
+
Resque.workers.select do |w|
|
51
|
+
w.queues == [Config.queue] && !w.shutdown?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
module Director
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.overwrite_perform
|
8
|
+
base.instance_eval do
|
9
|
+
def singleton_method_added(name)
|
10
|
+
return if name != :perform
|
11
|
+
overwrite_perform
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def direct(options={})
|
18
|
+
Config.setup(options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def overwrite_perform
|
22
|
+
class_eval do |klass|
|
23
|
+
if klass.respond_to?('perform') && !klass.respond_to?('custom_perform')
|
24
|
+
klass.instance_eval do
|
25
|
+
def custom_perform(*args)
|
26
|
+
args.pop unless retrieve_timestamp(args.last).nil?
|
27
|
+
original_perform(*args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class << klass
|
32
|
+
alias_method :original_perform, :perform
|
33
|
+
alias_method :perform, :custom_perform
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_enqueue_scale_workers(*args)
|
40
|
+
Config.queue = @queue.to_s
|
41
|
+
Scaler.scale_within_requirements
|
42
|
+
end
|
43
|
+
|
44
|
+
def before_perform_direct_workers(*args)
|
45
|
+
return unless scaling_config_set?
|
46
|
+
Config.queue = @queue.to_s
|
47
|
+
time_stamp = retrieve_timestamp(args.pop)
|
48
|
+
start_time = time_stamp.nil? ? Time.now.utc : Time.at(time_stamp.to_i).utc
|
49
|
+
|
50
|
+
time_through_queue = Time.now.utc - start_time
|
51
|
+
jobs_in_queue = Resque.size(@queue.to_s)
|
52
|
+
|
53
|
+
if scale_up?(time_through_queue, jobs_in_queue)
|
54
|
+
Scaler.scale_up
|
55
|
+
elsif scale_down?(time_through_queue, jobs_in_queue)
|
56
|
+
Scaler.scale_down
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def after_perform_direct_workers(*args)
|
61
|
+
jobs_in_queue = Resque.size(@queue.to_s)
|
62
|
+
Scaler.scale_down_to_minimum if jobs_in_queue == 0
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_failure_direct_workers(*args)
|
66
|
+
jobs_in_queue = Resque.size(@queue.to_s)
|
67
|
+
Scaler.scale_down_to_minimum if jobs_in_queue == 0
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def retrieve_timestamp(timestamp)
|
73
|
+
return nil unless timestamp.class.to_s == "Hash"
|
74
|
+
timestamp['resdirecttime'] || timestamp[:resdirecttime]
|
75
|
+
end
|
76
|
+
|
77
|
+
def scaling_config_set?
|
78
|
+
Config.max_time > 0 || Config.max_queue > 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def scale_up?(time_through_queue, jobs_in_queue)
|
82
|
+
time_limits = Config.max_time > 0 && time_through_queue > Config.max_time
|
83
|
+
queue_limits = Config.max_queue > 0 && jobs_in_queue > Config.max_queue
|
84
|
+
time_limits || queue_limits
|
85
|
+
end
|
86
|
+
|
87
|
+
def scale_down?(time_through_queue, jobs_in_queue)
|
88
|
+
time_limits = Config.max_time > 0 && time_through_queue < (Config.max_time/2)
|
89
|
+
queue_limits = Config.max_queue > 0 && jobs_in_queue < (Config.max_queue/2)
|
90
|
+
(Config.max_time <= 0 || time_limits) && (Config.max_queue <= 0 || queue_limits)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{resque-director}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{Nolan Frausto}]
|
12
|
+
s.date = %q{2011-08-20}
|
13
|
+
s.description = %q{resque plugin for dynamically adding/removing workers to a queue}
|
14
|
+
s.email = %q{nrfrausto@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/resque-director.rb",
|
28
|
+
"lib/resque/plugins/director.rb",
|
29
|
+
"lib/resque/plugins/director/config.rb",
|
30
|
+
"lib/resque/plugins/director/lifecycle.rb",
|
31
|
+
"lib/resque/plugins/director/scaler.rb",
|
32
|
+
"lib/resque/plugins/director/worker_tracker.rb",
|
33
|
+
"resque-director.gemspec",
|
34
|
+
"spec/redis-test.conf",
|
35
|
+
"spec/resque/plugins/director/config_spec.rb",
|
36
|
+
"spec/resque/plugins/director/lifecycle_spec.rb",
|
37
|
+
"spec/resque/plugins/director/scaler_spec.rb",
|
38
|
+
"spec/resque/plugins/director/worker_tracker_spec.rb",
|
39
|
+
"spec/resque/plugins/director_spec.rb",
|
40
|
+
"spec/spec_helper.rb",
|
41
|
+
"spec/support/test_job.rb"
|
42
|
+
]
|
43
|
+
s.homepage = %q{http://github.com/frausto/resque-director}
|
44
|
+
s.licenses = [%q{MIT}]
|
45
|
+
s.require_paths = [%q{lib}]
|
46
|
+
s.rubygems_version = %q{1.8.8}
|
47
|
+
s.summary = %q{resque plugin for dynamically adding/removing workers to a queue}
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
54
|
+
s.add_runtime_dependency(%q<resque>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
56
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
58
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<json>, [">= 0"])
|
61
|
+
s.add_dependency(%q<resque>, [">= 0"])
|
62
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
65
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<json>, [">= 0"])
|
69
|
+
s.add_dependency(%q<resque>, [">= 0"])
|
70
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
73
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|