Permalink
Browse files

initial version

  • Loading branch information...
1 parent 1dc430e commit 08601f4cc5eaf315200ee99c74b0005d4ff0814d @kristianmandrup committed Apr 28, 2012
View
@@ -28,22 +28,22 @@ pkg
#
# For MacOS:
#
-#.DS_Store
+.DS_Store
# For TextMate
-#*.tmproj
+*.tmproj
#tmtags
# For emacs:
-#*~
-#\#*
-#.\#*
+*~
+\#*
+.\#*
# For vim:
-#*.swp
+*.swp
# For redcar:
-#.redcar
+.redcar
# For rubinius:
-#*.rbc
+*.rbc
View
@@ -1,14 +1,12 @@
-source "http://rubygems.org"
-# Add dependencies required to use your gem here.
-# Example:
-# gem "activesupport", ">= 2.3.5"
+source :rubygems
+
+gem 'resque', '>= 1.10.0'
+gem 'heroku'
-# Add dependencies to develop your gem here.
-# Include everything needed to run rake, tests, features, etc.
group :development do
- gem "rspec", "~> 2.8.0"
- gem "rdoc", "~> 3.12"
- gem "bundler", "~> 1.0.0"
- gem "jeweler", "~> 1.8.3"
- gem "rcov", ">= 0"
+ gem "rspec", "~> 2.8.0"
+ gem "rdoc", "~> 3.12"
+ gem "bundler", "~> 1.1.0"
+ gem "jeweler", "~> 1.8.3"
+ gem "simplecov",">= 0.5"
end
View
@@ -0,0 +1,70 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ addressable (2.2.7)
+ diff-lcs (1.1.3)
+ git (1.2.5)
+ heroku (2.25.0)
+ launchy (>= 0.3.2)
+ netrc (~> 0.7.1)
+ rest-client (~> 1.6.1)
+ rubyzip
+ jeweler (1.8.3)
+ bundler (~> 1.0)
+ git (>= 1.2.5)
+ rake
+ rdoc
+ json (1.7.0)
+ launchy (2.1.0)
+ addressable (~> 2.2.6)
+ mime-types (1.18)
+ multi_json (1.3.2)
+ netrc (0.7.1)
+ rack (1.4.1)
+ rack-protection (1.2.0)
+ rack
+ rake (0.9.2.2)
+ rdoc (3.12)
+ json (~> 1.4)
+ redis (2.2.2)
+ redis-namespace (1.0.3)
+ redis (< 3.0.0)
+ resque (1.20.0)
+ multi_json (~> 1.0)
+ redis-namespace (~> 1.0.2)
+ sinatra (>= 0.9.2)
+ vegas (~> 0.1.2)
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
+ rspec (2.8.0)
+ rspec-core (~> 2.8.0)
+ rspec-expectations (~> 2.8.0)
+ rspec-mocks (~> 2.8.0)
+ rspec-core (2.8.0)
+ rspec-expectations (2.8.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.8.0)
+ rubyzip (0.9.8)
+ simplecov (0.6.2)
+ multi_json (~> 1.3)
+ simplecov-html (~> 0.5.3)
+ simplecov-html (0.5.3)
+ sinatra (1.3.2)
+ rack (~> 1.3, >= 1.3.6)
+ rack-protection (~> 1.2)
+ tilt (~> 1.3, >= 1.3.3)
+ tilt (1.3.3)
+ vegas (0.1.11)
+ rack (>= 1.0.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bundler (~> 1.1.0)
+ heroku
+ jeweler (~> 1.8.3)
+ rdoc (~> 3.12)
+ resque (>= 1.10.0)
+ rspec (~> 2.8.0)
+ simplecov (>= 0.5)
View
@@ -0,0 +1,49 @@
+# Heroku Auto-scale
+
+Adapted from: [Auto-scale Your Resque Workers On Heroku](https://gist.github.com/501160)
+
+## Configure auto-scaling
+
+The `job_counts` is list that is used to define how many jobs are run for the number of workers as determined by the index in the list:
+
+```ruby
+HerokuResque::AutoScale.job_counts[2] = 22 # 22 max jobs for 2 workers
+HerokuResque::AutoScale.job_counts = [1,4,8,16,32,64]
+```
+
+## Usage
+
+```ruby
+class ScalingJob
+ extend HerokuResque::AutoScale
+
+ def self.perform
+ # Do something long running
+ end
+end
+```
+
+## Configure Heroku stack used
+
+By default this gem assumes you are running on the 'cedar' stack.
+You can customize the Heroku stack used like this:
+
+`HerokuStack.name = 'my-stack'`
+
+We might have to adjust the code in order to support different stacks with different Process models in the future...
+
+## Contributing to heroku-auto_scale
+
+* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
+* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
+* Fork the project.
+* Start a feature/bugfix branch.
+* Commit and push until you are happy with your contribution.
+* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
+* 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.
+
+## Copyright
+
+Copyright (c) 2012 Kristian Mandrup. See LICENSE.txt for
+further details.
+
View
@@ -1,19 +0,0 @@
-= heroku-auto_scale
-
-Description goes here.
-
-== Contributing to heroku-auto_scale
-
-* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
-* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
-* Fork the project.
-* Start a feature/bugfix branch.
-* Commit and push until you are happy with your contribution.
-* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
-* 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.
-
-== Copyright
-
-Copyright (c) 2012 Kristian Mandrup. See LICENSE.txt for
-further details.
-
View
@@ -17,8 +17,8 @@ Jeweler::Tasks.new do |gem|
gem.name = "heroku-auto_scale"
gem.homepage = "http://github.com/kristianmandrup/heroku-auto_scale"
gem.license = "MIT"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{Auto-scale jobs per worker on Heroku}
+ gem.description = %Q{Lets you auto-scale jobs per worker on Heroku}
gem.email = "kmandrup@gmail.com"
gem.authors = ["Kristian Mandrup"]
# dependencies defined in Gemfile
View
@@ -1 +1 @@
-0.0.0
+0.1.0
@@ -0,0 +1,66 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = "heroku-auto_scale"
+ s.version = "0.1.0"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Kristian Mandrup"]
+ s.date = "2012-04-28"
+ s.description = "Lets you auto-scale jobs per worker on Heroku"
+ s.email = "kmandrup@gmail.com"
+ s.extra_rdoc_files = [
+ "LICENSE.txt",
+ "README.md"
+ ]
+ s.files = [
+ ".document",
+ ".rspec",
+ "Gemfile",
+ "LICENSE.txt",
+ "Rakefile",
+ "VERSION",
+ "lib/heroku-auto_scale.rb",
+ "spec/heroku-auto_scale_spec.rb",
+ "spec/spec_helper.rb"
+ ]
+ s.homepage = "http://github.com/kristianmandrup/heroku-auto_scale"
+ s.licenses = ["MIT"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = "1.8.22"
+ s.summary = "Auto-scale jobs per worker on Heroku"
+
+ if s.respond_to? :specification_version then
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_runtime_dependency(%q<resque>, [">= 1.10.0"])
+ s.add_runtime_dependency(%q<heroku>, [">= 0"])
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
+ s.add_development_dependency(%q<bundler>, ["~> 1.1.0"])
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
+ s.add_development_dependency(%q<simplecov>, [">= 0.5"])
+ else
+ s.add_dependency(%q<resque>, [">= 1.10.0"])
+ s.add_dependency(%q<heroku>, [">= 0"])
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
+ s.add_dependency(%q<simplecov>, [">= 0.5"])
+ end
+ else
+ s.add_dependency(%q<resque>, [">= 1.10.0"])
+ s.add_dependency(%q<heroku>, [">= 0"])
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
+ s.add_dependency(%q<simplecov>, [">= 0.5"])
+ end
+end
+
@@ -0,0 +1,3 @@
+require 'heroku'
+require 'heroku_resque/auto_scale'
+require 'heroku_stack'
@@ -0,0 +1,56 @@
+require 'heroku_resque/auto_scale/scaler'
+
+module HerokuResque
+ module AutoScale
+ def after_perform_scale_down(*args)
+ # Nothing fancy, just shut everything down if we have no jobs
+ Scaler.workers = 0 if Scaler.job_count.zero?
+ end
+
+ attr_writer :auto_scale_config
+
+ class << self
+ attr_writer :default_config, :job_counts
+
+ def job_counts
+ @job_counts ||= [1, 15, 25, 40, 60, 100, 150]
+ end
+
+ def default_config
+ (1..5).to_a.map do |workers|
+ worker_config workers
+ end
+ end
+
+ protected
+
+ def worker_config workers
+ {:workers => workers, :job_count => job_counts[workers]}
+ end
+ end
+
+ # To adjust:
+ #
+ # auto_scale_config[2] = {:workers => 2, :job_count => 20}
+ #
+ def auto_scale_config
+ @auto_scale_config ||= HerokuResque::AutoScale.default_config
+ end
+
+ def after_enqueue_scale_up(*args)
+ auto_scale_config.reverse_each do |scale_info|
+ # Run backwards so it gets set to the highest value first
+ # Otherwise if there were 70 jobs, it would get set to 1, then 2, then 3, etc
+
+ # If we have a job count greater than or equal to the job limit for this scale info
+ if Scaler.job_count >= scale_info[:job_count]
+ # Set the number of workers unless they are already set to a level we want. Don't scale down here!
+ if Scaler.workers <= scale_info[:workers]
+ Scaler.workers = scale_info[:workers]
+ end
+ break # We've set or ensured that the worker count is high enough
+ end
+ end
+ end
+ end
+end
@@ -0,0 +1,35 @@
+module HerokuResque
+ module AutoScale
+ module Scaler
+ class << self
+ @@heroku = Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASS'])
+
+ def workers
+ case HerokuStack.name.to_sym
+ when :cedar
+ @@heroku.ps(ENV['HEROKU_APP']).count { |a| a["process"] =~ /worker/ }
+ else
+ @@heroku.info(ENV['HEROKU_APP'])[:workers].to_i
+ end
+ end
+
+ def workers=(qty)
+ case HerokuStack.name.to_sym
+ when :cedar
+ @@heroku.ps_scale(ENV['HEROKU_APP'], :type=>'worker', :qty=>qty)
+ else
+ @@heroku.set_workers(ENV['HEROKU_APP'], qty)
+ end
+ end
+
+ def working_count
+ Resque.info[:working].to_i
+ end
+
+ def job_count
+ Resque.info[:pending].to_i
+ end
+ end
+ end
+ end
+end
View
@@ -0,0 +1,13 @@
+class HerokuStack
+ class << self
+ attr_writer :name
+
+ def name
+ @name ||= default_name
+ end
+
+ def default_name
+ 'cedar'
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 08601f4

Please sign in to comment.