resque-heroku-autoscaler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/GEMFILE ADDED
@@ -0,0 +1,12 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'resque', '>= 1.8'
4
+ gem 'heroku', '1.11.0'
5
+
6
+ group :development do
7
+ gem "rspec", "~> 2.0"
8
+ gem 'rr', '1.0.2'
9
+ gem 'echoe'
10
+ gem 'rake'
11
+ end
12
+
data/MIT.LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Alexander Murmann
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.md ADDED
@@ -0,0 +1,28 @@
1
+ Resque Heroku Autoscaler
2
+ ===========
3
+
4
+ A [Resque][rq] plugin. Requires Resque 1.8 and the Heroku gem (I only testet with 1.11.0).
5
+
6
+ This gem scales your Heroku workers according to the number of pending Resque jobs. The original idea comes from Daniel Huckstep's [blog post on the topic][dh]
7
+
8
+ Just extend your job class with esque::Plugins::HerokuAutoscaler.
9
+
10
+
11
+ For example:
12
+
13
+ require 'resque/plugins/heroku_autoscaler'
14
+
15
+ class TestJob
16
+ extend Resque::Plugins::HerokuAutoscaler
17
+
18
+ @queue = :test
19
+
20
+ def
21
+ end
22
+
23
+ When you add the job to your Resque queue, a new worker will be started if there isn't already one. If all jobs in the queue are processed the worker will be stopped again, keeping your costs low.
24
+
25
+ Currently there is no way build in to set how many workers to are being started. I plan on adding that functionality soon.
26
+
27
+ [dh]: http://blog.darkhax.com/2010/07/30/auto-scale-your-resque-workers-on-heroku
28
+ [rq]: http://github.com/defunkt/resque
@@ -0,0 +1,23 @@
1
+ module Resque
2
+ module Plugins
3
+ module HerokuAutoscaler
4
+ @@heroku_client = nil
5
+
6
+ def after_enqueue_scale_workers_up(*args)
7
+ set_workers(1)
8
+ end
9
+
10
+ def after_perform_scale_workers_down(*args)
11
+ set_workers(0) if Resque.info[:pending] == 0
12
+ end
13
+
14
+ def set_workers(number_of_workers)
15
+ heroku_client.set_workers(ENV['HEROKU_APP'], number_of_workers)
16
+ end
17
+
18
+ def heroku_client
19
+ @@heroku_client || @@heroku_client = Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASS'])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,119 @@
1
+ require 'rspec'
2
+ require 'heroku'
3
+ require 'resque'
4
+ require 'resque/plugins/resque_heroku_autoscaler'
5
+
6
+ class TestJob
7
+ extend Resque::Plugins::HerokuAutoscaler
8
+
9
+ @queue = :test
10
+ end
11
+
12
+ class AnotherJob
13
+ extend Resque::Plugins::HerokuAutoscaler
14
+
15
+ @queue = :test
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ config.mock_with :rr
20
+ end
21
+
22
+ describe Resque::Plugins::HerokuAutoscaler do
23
+ it "should be a valid Resque plugin" do
24
+ lambda { Resque::Plugin.lint(Resque::Plugins::HerokuAutoscaler) }.should_not raise_error
25
+ end
26
+
27
+ describe ".after_enqueue_scale_workers_up" do
28
+ it "should add the hook" do
29
+ Resque::Plugin.after_enqueue_hooks(TestJob).should include("after_enqueue_scale_workers_up")
30
+ end
31
+
32
+ it "should take whatever args Resque hands in" do
33
+ stub(Heroku::Client).new { stub!.set_workers }
34
+
35
+ lambda { TestJob.after_enqueue_scale_workers_up("some", "random", "aguments", 42) }.should_not raise_error
36
+ end
37
+
38
+ it "should create one worker" do
39
+ stub(TestJob).workers { 0 }
40
+ mock(TestJob).set_workers(1)
41
+ TestJob.after_enqueue_scale_workers_up
42
+ end
43
+ end
44
+
45
+ describe ".after_perform_scale_workers_down" do
46
+
47
+ it "should add the hook" do
48
+ Resque::Plugin.after_hooks(TestJob).should include("after_perform_scale_workers_down")
49
+ end
50
+
51
+ it "should take whatever args Resque hands in" do
52
+ Resque::Plugins::HerokuAutoscaler.class_eval("@@heroku_client = nil")
53
+ stub(Heroku::Client).new { stub!.set_workers }
54
+
55
+ lambda { TestJob.after_perform_scale_workers_down("some", "random", "aguments", 42) }.should_not raise_error
56
+ end
57
+
58
+ context "when the queue is empty" do
59
+ before do
60
+ stub(Resque).info { {:pending => 0} }
61
+ end
62
+
63
+ it "should set workers to 0" do
64
+ mock(TestJob).set_workers(0)
65
+ TestJob.after_perform_scale_workers_down
66
+ end
67
+ end
68
+
69
+ context "when the queue is not empty" do
70
+ before do
71
+ stub(Resque).info { {:pending => 1} }
72
+ end
73
+
74
+ it "should not change workers" do
75
+ dont_allow(TestJob).set_workers
76
+ TestJob.after_perform_scale_workers_down
77
+ end
78
+ end
79
+ end
80
+
81
+ describe ".set_workers" do
82
+ it "should use the Heroku client to set the workers" do
83
+ ENV['HEROKU_APP'] = 'some app name'
84
+ mock(TestJob).heroku_client { mock!.set_workers('some app name', 10) }
85
+ TestJob.set_workers(10)
86
+ end
87
+ end
88
+
89
+ describe ".heroku_client" do
90
+ before do
91
+ ENV['HEROKU_USER'] = 'john doe'
92
+ ENV['HEROKU_PASS'] = 'password'
93
+ end
94
+
95
+ it "should return a heroku client" do
96
+ Resque::Plugins::HerokuAutoscaler.class_eval("@@heroku_client = nil")
97
+ TestJob.heroku_client.should be_a(Heroku::Client)
98
+ end
99
+
100
+ it "should use the right username and password" do
101
+ Resque::Plugins::HerokuAutoscaler.class_eval("@@heroku_client = nil")
102
+ mock(Heroku::Client).new('john doe', 'password')
103
+ TestJob.heroku_client
104
+ end
105
+
106
+ it "should return the same client for multiple jobs" do
107
+ a = 0
108
+ stub(Heroku::Client).new { a += 1 }
109
+ TestJob.heroku_client.should == TestJob.heroku_client
110
+ end
111
+
112
+ it "should share the same client across differnet job types" do
113
+ a = 0
114
+ stub(Heroku::Client).new { a += 1 }
115
+
116
+ TestJob.heroku_client.should == AnotherJob.heroku_client
117
+ end
118
+ end
119
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque-heroku-autoscaler
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Alexander Murmann
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-06 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: resque
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 31
30
+ segments:
31
+ - 1
32
+ - 8
33
+ version: "1.8"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: heroku
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ description:
51
+ email: ajmurmann@gmail.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - README.md
60
+ - MIT.LICENSE
61
+ - GEMFILE
62
+ - lib/resque/plugins/resque_heroku_autoscaler.rb
63
+ - spec/resque_heroku_autoscaler_spec.rb
64
+ has_rdoc: true
65
+ homepage: https://github.com/ajmurmann/resque-heroku-autoscaler
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project:
94
+ rubygems_version: 1.5.0
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Resque plugin to autoscale your workers on Heroku
98
+ test_files: []
99
+