rcarvalho-workless 1.0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +100 -0
- data/lib/workless.rb +4 -0
- data/lib/workless/initialize.rb +3 -0
- data/lib/workless/railtie.rb +10 -0
- data/lib/workless/scaler.rb +44 -0
- data/lib/workless/scalers/base.rb +39 -0
- data/lib/workless/scalers/heroku.rb +28 -0
- data/lib/workless/scalers/heroku_cedar.rb +28 -0
- data/lib/workless/scalers/local.rb +32 -0
- data/lib/workless/scalers/null.rb +17 -0
- data/rails/init.rb +1 -0
- metadata +111 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 lostboy
|
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,100 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/lostboy/workless.png?branch=master)](http://travis-ci.org/lostboy/workless)
|
2
|
+
|
3
|
+
# Workless
|
4
|
+
|
5
|
+
This is an addon for delayed_job (> 2.0.0) http://github.com/collectiveidea/delayed_job
|
6
|
+
It is designed to be used when you're using Heroku as a host and have the need to do background work with delayed job but you don't want to leave the workers running all the time as it costs money.
|
7
|
+
|
8
|
+
By adding the gem to your project and configuring our Heroku app with some config variables workless should do the rest.
|
9
|
+
|
10
|
+
## Update
|
11
|
+
|
12
|
+
Version 1.0.0 has been released, this brings compatibility with delayed_job 3 and compatibility with Rails 2.3.x and up.
|
13
|
+
|
14
|
+
## Compatibility
|
15
|
+
|
16
|
+
Workless should work correctly with Rubies 1.8.7, ree, 1.9.2 and 1.9.3. It is compatible with Delayed Job since version 2.0.7 up to the latest version 3.0.1, the table below shows tested compatibility with ruby, rails and delayed_job
|
17
|
+
|
18
|
+
Ruby | Rails | Delayed Job
|
19
|
+
---------- | ------ | -----
|
20
|
+
1.8.7-ree | 2.1.14 | 2.0.7
|
21
|
+
1.9.2 | 3.2 | 2.1.4
|
22
|
+
1.9.2 | 3.2 | 3.0.1
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add the workless gem and the delayed_job gem to your project Gemfile and update your bundle. Its is recommended to specify the gem version for delayed_job especially if you are using rails 2.3.x which doesn't work with the latest delayed_job
|
27
|
+
|
28
|
+
### For rails 2.3.x the latest compatible delayed_job is 2.0.7
|
29
|
+
|
30
|
+
<pre>
|
31
|
+
gem "delayed_job", "2.0.7"
|
32
|
+
gem "workless", "~> 1.0.1"
|
33
|
+
</pre>
|
34
|
+
|
35
|
+
### For rails 3.x with delayed_job 2.1.x
|
36
|
+
|
37
|
+
<pre>
|
38
|
+
gem "delayed_job", "~> 2.1.4"
|
39
|
+
gem "workless", "~> 1.0.1"
|
40
|
+
</pre>
|
41
|
+
|
42
|
+
### For rails 3.x with latest delayed_job 3.x using active record
|
43
|
+
|
44
|
+
<pre>
|
45
|
+
gem "delayed_job_active_record"
|
46
|
+
gem "workless", "~> 1.0.1"
|
47
|
+
</pre>
|
48
|
+
|
49
|
+
If you don't specify delayed_job in your Gemfile workless will bring it in, most likly the latest version (3.0.1)
|
50
|
+
|
51
|
+
Add your Heroku username / password as config vars to your Heroku instance, the same one you log in to Heroku with.
|
52
|
+
[You may also use your API key as the password](https://github.com/heroku/heroku/issues/103).
|
53
|
+
|
54
|
+
<pre>
|
55
|
+
heroku config:add HEROKU_USER=yourusername HEROKU_PASSWORD=yourpassword
|
56
|
+
</pre>
|
57
|
+
|
58
|
+
And for cedar apps add the app name
|
59
|
+
|
60
|
+
<pre>
|
61
|
+
heroku config:add APP_NAME=yourherokuappname
|
62
|
+
</pre>
|
63
|
+
|
64
|
+
## Failing Jobs
|
65
|
+
|
66
|
+
In the case of failed jobs Workless will only shut down the dj worker if all attempts have been tried. By default Delayed Job will try 25 times to process a job with ever increasing time delays between each unsucessful attempt. Because of this Workless configures Delayed Job to try failed jobs only 3 times to reduce the amount of time a worker can be running while trying to process them.
|
67
|
+
|
68
|
+
## Configuration
|
69
|
+
|
70
|
+
Workless can be disabled by using the null scaler that will ignore the workers requests to scale up and down. In an environment file add this in the config block:
|
71
|
+
|
72
|
+
<pre>
|
73
|
+
config.after_initialize do
|
74
|
+
Delayed::Job.scaler = :null
|
75
|
+
end
|
76
|
+
</pre>
|
77
|
+
|
78
|
+
There are three other scalers included. Note that if you are running on the Aspen or Bamboo stacks on Heroku and you don't explicitly specify the scaler, the heroku scaler will be used automatically.
|
79
|
+
|
80
|
+
<pre>
|
81
|
+
Delayed::Job.scaler = :heroku
|
82
|
+
Delayed::Job.scaler = :heroku_cedar
|
83
|
+
Delayed::Job.scaler = :local
|
84
|
+
</pre>
|
85
|
+
|
86
|
+
The local scaler uses @adamwiggins rush library http://github.com/adamwiggins/rush to start and stop workers on a local machine
|
87
|
+
|
88
|
+
The heroku scaler works on the Aspen and Bamboo stacks while the heroku_cedar scaler only works on the new Cedar stack.
|
89
|
+
|
90
|
+
## Note on Patches/Pull Requests
|
91
|
+
|
92
|
+
* Please fork the project, as you can see there are no tests and at present I don't know how to go about adding them so any advice would be welcome.
|
93
|
+
* Make your feature addition or bug fix.
|
94
|
+
* Commit, do not mess with rakefile, version, or history.
|
95
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
96
|
+
* Send me a pull request.
|
97
|
+
|
98
|
+
## Copyright
|
99
|
+
|
100
|
+
Copyright (c) 2010 lostboy. See LICENSE for details.
|
data/lib/workless.rb
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
Delayed::Worker.max_attempts = 3
|
2
|
+
Delayed::Backend::ActiveRecord::Job.send(:include, Delayed::Workless::Scaler) if defined?(Delayed::Backend::ActiveRecord::Job)
|
3
|
+
Delayed::Backend::Mongoid::Job.send(:include, Delayed::Workless::Scaler) if defined?(Delayed::Backend::Mongoid::Job)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'workless/scalers/heroku'
|
2
|
+
require 'workless/scalers/heroku_cedar'
|
3
|
+
require 'workless/scalers/local'
|
4
|
+
require 'workless/scalers/null'
|
5
|
+
|
6
|
+
module Delayed
|
7
|
+
module Workless
|
8
|
+
module Scaler
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.send :extend, ClassMethods
|
12
|
+
base.class_eval do
|
13
|
+
after_destroy "self.class.scaler.down"
|
14
|
+
before_create "self.class.scaler.up"
|
15
|
+
after_update "self.class.scaler.down", :unless => Proc.new {|r| r.failed_at.nil? }
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def scaler
|
22
|
+
@scaler ||= if ENV.include?("HEROKU_USER")
|
23
|
+
client = ::Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASSWORD'])
|
24
|
+
case client.info(ENV["APP_NAME"])[:stack]
|
25
|
+
when "cedar"
|
26
|
+
Scaler::HerokuCedar
|
27
|
+
else
|
28
|
+
Scaler::Heroku
|
29
|
+
end
|
30
|
+
else
|
31
|
+
Scaler::Local
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def scaler=(scaler)
|
36
|
+
@scaler = "Delayed::Workless::Scaler::#{scaler.to_s.camelize}".constantize
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'delayed_job'
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Workless
|
5
|
+
module Scaler
|
6
|
+
|
7
|
+
class Base
|
8
|
+
def self.jobs
|
9
|
+
Delayed::Job.all(:conditions => { :failed_at => nil })
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.calculate_num_workers
|
13
|
+
num_workers = self.workers
|
14
|
+
if num_workers.class == Fixnum
|
15
|
+
job_count = self.jobs.count
|
16
|
+
if job_count > 500
|
17
|
+
return 4 unless num_workers > 3
|
18
|
+
elsif job_count > 200
|
19
|
+
return 3 unless num_workers > 2
|
20
|
+
elsif job_count > 50
|
21
|
+
return 2 unless num_workers > 1
|
22
|
+
elsif job_count > 0
|
23
|
+
return 1 unless num_workers > 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module HerokuClient
|
30
|
+
|
31
|
+
def client
|
32
|
+
@client ||= ::Heroku::Client.new(ENV['HEROKU_USER'], ENV['HEROKU_PASSWORD'])
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'heroku'
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Workless
|
5
|
+
module Scaler
|
6
|
+
|
7
|
+
class Heroku < Base
|
8
|
+
|
9
|
+
extend Delayed::Workless::Scaler::HerokuClient
|
10
|
+
|
11
|
+
def self.up
|
12
|
+
nw = self.calculate_num_workers
|
13
|
+
client.set_workers(ENV['APP_NAME'], nw) if nw
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
client.set_workers(ENV['APP_NAME'], 0) unless self.workers == 0 or self.jobs.count > 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.workers
|
21
|
+
client.info(ENV['APP_NAME'])[:workers].to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'heroku'
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Workless
|
5
|
+
module Scaler
|
6
|
+
|
7
|
+
class HerokuCedar < Base
|
8
|
+
|
9
|
+
extend Delayed::Workless::Scaler::HerokuClient
|
10
|
+
|
11
|
+
def self.up
|
12
|
+
nw = self.calculate_num_workers
|
13
|
+
client.ps_scale(ENV['APP_NAME'], :type => 'worker', :qty => nw) if nw
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
client.ps_scale(ENV['APP_NAME'], :type => 'worker', :qty => 0) unless self.workers == 0 or self.jobs.count > 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.workers
|
21
|
+
client.ps(ENV['APP_NAME']).count { |p| p["process"] =~ /worker\.\d?/ }
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rush'
|
2
|
+
|
3
|
+
module Delayed
|
4
|
+
module Workless
|
5
|
+
module Scaler
|
6
|
+
|
7
|
+
class Local < Base
|
8
|
+
|
9
|
+
def self.up
|
10
|
+
if self.workers == 0
|
11
|
+
Rush::Box.new[Rails.root].bash("script/delayed_job start -i workless", :background => true)
|
12
|
+
sleep 1
|
13
|
+
end
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
unless jobs.count > 0 and workers > 0
|
19
|
+
Rush::Box.new[Rails.root].bash("script/delayed_job stop -i workless", :background => true)
|
20
|
+
end
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.workers
|
25
|
+
Rush::Box.new.processes.filter(:cmdline => /delayed_job start -i workless|delayed_job.workless/).size
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../lib/workless/initialize"
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rcarvalho-workless
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.2.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- lostboy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &2156064120 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156064120
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: heroku
|
27
|
+
requirement: &2156063120 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156063120
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rush
|
38
|
+
requirement: &2156062120 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2156062120
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: delayed_job
|
49
|
+
requirement: &2156061140 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.0.7
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2156061140
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: &2156060360 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2156060360
|
69
|
+
description: Extension to Delayed Job to enable workers to scale up when needed
|
70
|
+
email: paul.crabtree@gmail.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- rails/init.rb
|
76
|
+
- lib/workless/initialize.rb
|
77
|
+
- lib/workless/railtie.rb
|
78
|
+
- lib/workless/scaler.rb
|
79
|
+
- lib/workless/scalers/base.rb
|
80
|
+
- lib/workless/scalers/heroku.rb
|
81
|
+
- lib/workless/scalers/heroku_cedar.rb
|
82
|
+
- lib/workless/scalers/local.rb
|
83
|
+
- lib/workless/scalers/null.rb
|
84
|
+
- lib/workless.rb
|
85
|
+
- LICENSE
|
86
|
+
- README.md
|
87
|
+
homepage: http://github.com/lostboy/workless
|
88
|
+
licenses: []
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 1.3.6
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.8.6
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Use delayed job workers only when theyre needed on Heroku
|
111
|
+
test_files: []
|