hirefire 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -0
- data/lib/hirefire.rb +6 -3
- data/lib/hirefire/backend.rb +7 -2
- data/lib/hirefire/backend/delayed_job/active_record.rb +3 -1
- data/lib/hirefire/backend/delayed_job/active_record_2.rb +35 -0
- data/lib/hirefire/backend/delayed_job/mongoid.rb +3 -1
- data/lib/hirefire/backend/resque/redis.rb +21 -3
- data/lib/hirefire/configuration.rb +7 -0
- data/lib/hirefire/environment.rb +1 -1
- data/lib/hirefire/environment/base.rb +16 -6
- data/lib/hirefire/environment/heroku.rb +6 -0
- data/lib/hirefire/initializer.rb +2 -1
- data/lib/hirefire/version.rb +1 -1
- data/lib/hirefire/workers/delayed_job/worker.rb +8 -1
- data/lib/hirefire/workers/resque.rb +6 -5
- data/lib/hirefire/workers/resque/worker.rb +1 -1
- data/spec/configuration_spec.rb +3 -0
- data/spec/environment_spec.rb +19 -0
- metadata +5 -24
data/README.md
CHANGED
@@ -44,6 +44,7 @@ And that's it. Next time you deploy to [Heroku](http://heroku.com/) it'll automa
|
|
44
44
|
HireFire.configure do |config|
|
45
45
|
config.environment = nil # default in production is :heroku. default in development is :noop
|
46
46
|
config.max_workers = 5 # default is 1
|
47
|
+
config.min_workers = 0 # default is 0
|
47
48
|
config.job_worker_ratio = [
|
48
49
|
{ :jobs => 1, :workers => 1 },
|
49
50
|
{ :jobs => 15, :workers => 2 },
|
data/lib/hirefire.rb
CHANGED
@@ -44,8 +44,9 @@ module HireFire
|
|
44
44
|
##
|
45
45
|
# HireFire::Backend::DelayedJob namespace
|
46
46
|
module DelayedJob
|
47
|
-
autoload :ActiveRecord,
|
48
|
-
autoload :
|
47
|
+
autoload :ActiveRecord, File.join(DELAYED_JOB_PATH, 'active_record')
|
48
|
+
autoload :ActiveRecord2, File.join(DELAYED_JOB_PATH, 'active_record_2')
|
49
|
+
autoload :Mongoid, File.join(DELAYED_JOB_PATH, 'mongoid')
|
49
50
|
end
|
50
51
|
|
51
52
|
##
|
@@ -72,6 +73,7 @@ module HireFire
|
|
72
73
|
# HireFire.configure do |config|
|
73
74
|
# config.environment = nil
|
74
75
|
# config.max_workers = 5
|
76
|
+
# config.min_workers = 0
|
75
77
|
# config.job_worker_ratio = [
|
76
78
|
# { :jobs => 1, :workers => 1 },
|
77
79
|
# { :jobs => 15, :workers => 2 },
|
@@ -103,9 +105,10 @@ end
|
|
103
105
|
# in their application manually, after loading the worker library (either "Delayed Job" or "Resque")
|
104
106
|
# and the desired mapper (ActiveRecord, Mongoid or Redis)
|
105
107
|
if defined?(Rails)
|
106
|
-
if Rails
|
108
|
+
if defined?(Rails::Railtie)
|
107
109
|
require File.join(HireFire::HIREFIRE_PATH, 'railtie')
|
108
110
|
else
|
109
111
|
HireFire::Initializer.initialize!
|
110
112
|
end
|
111
113
|
end
|
114
|
+
|
data/lib/hirefire/backend.rb
CHANGED
@@ -16,9 +16,13 @@ module HireFire
|
|
16
16
|
|
17
17
|
##
|
18
18
|
# Delayed Job specific backends
|
19
|
-
if defined?(::Delayed
|
19
|
+
if defined?(::Delayed)
|
20
20
|
if defined?(::Delayed::Backend::ActiveRecord::Job)
|
21
|
-
|
21
|
+
if defined?(::ActiveRecord::Relation)
|
22
|
+
base.send(:include, HireFire::Backend::DelayedJob::ActiveRecord)
|
23
|
+
else
|
24
|
+
base.send(:include, HireFire::Backend::DelayedJob::ActiveRecord2)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
if defined?(::Delayed::Backend::Mongoid::Job)
|
@@ -35,3 +39,4 @@ module HireFire
|
|
35
39
|
|
36
40
|
end
|
37
41
|
end
|
42
|
+
|
@@ -18,9 +18,11 @@ module HireFire
|
|
18
18
|
|
19
19
|
##
|
20
20
|
# Counts the amount of jobs that are locked by a worker
|
21
|
+
# There is no other performant way to determine the amount
|
22
|
+
# of workers there currently are
|
21
23
|
#
|
22
24
|
# @return [Fixnum] the amount of (assumably working) workers
|
23
|
-
def
|
25
|
+
def working
|
24
26
|
::Delayed::Job.
|
25
27
|
where('locked_by IS NOT NULL').count
|
26
28
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HireFire
|
4
|
+
module Backend
|
5
|
+
module DelayedJob
|
6
|
+
module ActiveRecord2
|
7
|
+
|
8
|
+
##
|
9
|
+
# Counts the amount of queued jobs in the database,
|
10
|
+
# failed jobs are excluded from the sum
|
11
|
+
#
|
12
|
+
# @return [Fixnum] the amount of pending jobs
|
13
|
+
def jobs
|
14
|
+
::Delayed::Job.all(
|
15
|
+
:conditions => ['failed_at IS NULL and run_at <= ?', Time.now.utc]
|
16
|
+
).count
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Counts the amount of jobs that are locked by a worker
|
21
|
+
# There is no other performant way to determine the amount
|
22
|
+
# of workers there currently are
|
23
|
+
#
|
24
|
+
# @return [Fixnum] the amount of (assumably working) workers
|
25
|
+
def working
|
26
|
+
::Delayed::Job.all(
|
27
|
+
:conditions => 'locked_by IS NOT NULL'
|
28
|
+
).count
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -19,9 +19,11 @@ module HireFire
|
|
19
19
|
|
20
20
|
##
|
21
21
|
# Counts the amount of jobs that are locked by a worker
|
22
|
+
# There is no other performant way to determine the amount
|
23
|
+
# of workers there currently are
|
22
24
|
#
|
23
25
|
# @return [Fixnum] the amount of (assumably working) workers
|
24
|
-
def
|
26
|
+
def working
|
25
27
|
::Delayed::Job.
|
26
28
|
where(:locked_by.ne => nil).count
|
27
29
|
end
|
@@ -6,12 +6,30 @@ module HireFire
|
|
6
6
|
module Redis
|
7
7
|
|
8
8
|
##
|
9
|
-
# Counts the amount of
|
10
|
-
#
|
9
|
+
# Counts the amount of pending jobs in Redis
|
10
|
+
#
|
11
|
+
# Failed jobs are excluded because they are not listed as "pending"
|
12
|
+
# and jobs cannot be scheduled for the future in Resque
|
11
13
|
#
|
12
14
|
# @return [Fixnum]
|
13
15
|
def jobs
|
14
|
-
::Resque.info[:pending].to_i
|
16
|
+
::Resque.info[:pending].to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Counts the amount of workers
|
21
|
+
#
|
22
|
+
# @return [Fixnum]
|
23
|
+
def workers
|
24
|
+
::Resque.info[:workers].to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Counts the amount of jobs that are being processed by workers
|
29
|
+
#
|
30
|
+
# @return [Fixnum]
|
31
|
+
def working
|
32
|
+
::Resque.info[:working].to_i
|
15
33
|
end
|
16
34
|
|
17
35
|
end
|
@@ -9,6 +9,12 @@ module HireFire
|
|
9
9
|
# @return [Fixnum] default: 1
|
10
10
|
attr_accessor :max_workers
|
11
11
|
|
12
|
+
##
|
13
|
+
# Contains the min amount of workers that should always be running
|
14
|
+
#
|
15
|
+
# @return [Fixnum] default: 0
|
16
|
+
attr_accessor :min_workers
|
17
|
+
|
12
18
|
##
|
13
19
|
# Contains the job/worker ratio which determines
|
14
20
|
# how many workers need to be running depending on
|
@@ -33,6 +39,7 @@ module HireFire
|
|
33
39
|
# @return [HireFire::Configuration]
|
34
40
|
def initialize
|
35
41
|
@max_workers = 1
|
42
|
+
@min_workers = 0
|
36
43
|
@job_worker_ratio = [
|
37
44
|
{ :jobs => 1, :workers => 1 },
|
38
45
|
{ :jobs => 25, :workers => 2 },
|
data/lib/hirefire/environment.rb
CHANGED
@@ -19,6 +19,7 @@ module HireFire
|
|
19
19
|
#
|
20
20
|
# HireFire.configure do |config|
|
21
21
|
# config.max_workers = 5
|
22
|
+
# config.min_workers = 0
|
22
23
|
# config.job_worker_ratio = [
|
23
24
|
# { :jobs => 1, :workers => 1 },
|
24
25
|
# { :jobs => 15, :workers => 2 },
|
@@ -60,7 +61,7 @@ module HireFire
|
|
60
61
|
# @return [nil]
|
61
62
|
def hire
|
62
63
|
jobs_count = jobs
|
63
|
-
workers_count = workers
|
64
|
+
workers_count = workers || return
|
64
65
|
|
65
66
|
##
|
66
67
|
# Use "Standard Notation"
|
@@ -160,13 +161,13 @@ module HireFire
|
|
160
161
|
# or "updated, unless the job didn't fail"
|
161
162
|
#
|
162
163
|
# If there are workers active, but there are no more pending jobs,
|
163
|
-
# then fire all the workers
|
164
|
+
# then fire all the workers or set to the minimum_workers
|
164
165
|
#
|
165
166
|
# @return [nil]
|
166
167
|
def fire
|
167
|
-
if jobs == 0 and workers >
|
168
|
-
Logger.message("All queued jobs have been processed. Firing all workers.")
|
169
|
-
workers(
|
168
|
+
if jobs == 0 and workers > min_workers
|
169
|
+
Logger.message("All queued jobs have been processed. " + (min_workers > 0 ? "Setting workers to #{min_workers}." : "Firing all workers."))
|
170
|
+
workers(min_workers)
|
170
171
|
end
|
171
172
|
end
|
172
173
|
|
@@ -192,7 +193,16 @@ module HireFire
|
|
192
193
|
|
193
194
|
##
|
194
195
|
# Wrapper method for HireFire.configuration
|
195
|
-
# Returns the
|
196
|
+
# Returns the min amount of workers that should always be running
|
197
|
+
#
|
198
|
+
# @return [Fixnum] the min amount of workers that should always be running
|
199
|
+
def min_workers
|
200
|
+
HireFire.configuration.min_workers
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# Wrapper method for HireFire.configuration
|
205
|
+
# Returns the job/worker ratio array
|
196
206
|
#
|
197
207
|
# @return [Array] the array of hashes containing the job/worker ratio
|
198
208
|
def ratio
|
@@ -31,6 +31,12 @@ module HireFire
|
|
31
31
|
# Sets the amount of Delayed Job
|
32
32
|
# workers that need to be running on Heroku
|
33
33
|
client.set_workers(ENV['APP_NAME'], amount)
|
34
|
+
|
35
|
+
rescue RestClient::Exception
|
36
|
+
# Heroku library uses rest-client, currently, and it is quite
|
37
|
+
# possible to receive RestClient exceptions through the client.
|
38
|
+
HireFire::Logger.message("Worker query request failed with #{ $!.class.name } #{ $!.message }")
|
39
|
+
nil
|
34
40
|
end
|
35
41
|
|
36
42
|
##
|
data/lib/hirefire/initializer.rb
CHANGED
@@ -24,7 +24,7 @@ module HireFire
|
|
24
24
|
|
25
25
|
##
|
26
26
|
# Initialize Delayed::Job extensions if Delayed::Job is found
|
27
|
-
if defined?(::Delayed
|
27
|
+
if defined?(::Delayed)
|
28
28
|
##
|
29
29
|
# If DelayedJob is using ActiveRecord, then include
|
30
30
|
# HireFire::Environment in to the ActiveRecord Delayed Job Backend
|
@@ -71,3 +71,4 @@ module HireFire
|
|
71
71
|
|
72
72
|
end
|
73
73
|
end
|
74
|
+
|
data/lib/hirefire/version.rb
CHANGED
@@ -15,7 +15,13 @@ module Delayed
|
|
15
15
|
# except for the following:
|
16
16
|
#
|
17
17
|
# 1. All ouput will now go through the HireFire::Logger.
|
18
|
-
# 2.
|
18
|
+
# 2. Invoke the ::Delayed::Job.environment.hire method at every loop
|
19
|
+
# to see whether we need to hire more workers so that we can delegate
|
20
|
+
# this task to the workers, rather than the web servers to improve web-throughput
|
21
|
+
# by avoiding any unnecessary API calls to Heroku.
|
22
|
+
# If there are any workers running, then the front end will never invoke API calls
|
23
|
+
# since the worker(s) can handle this itself.
|
24
|
+
# 3. When HireFire cannot find any jobs to process it sends the "fire"
|
19
25
|
# signal to all workers, ending all the processes simultaneously. The reason
|
20
26
|
# we wait for all the processes to finish before sending the signal is because it'll
|
21
27
|
# otherwise interrupt workers and leave jobs unfinished.
|
@@ -29,6 +35,7 @@ module Delayed
|
|
29
35
|
queued = Delayed::Job.new
|
30
36
|
|
31
37
|
loop do
|
38
|
+
::Delayed::Job.environment.hire
|
32
39
|
result = nil
|
33
40
|
|
34
41
|
realtime = Benchmark.realtime do
|
@@ -16,11 +16,12 @@ module ::Resque
|
|
16
16
|
|
17
17
|
##
|
18
18
|
# HireFire Hook
|
19
|
-
# After a new job gets
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
23
|
-
|
19
|
+
# After a new job gets enqueued we check to see if there are currently
|
20
|
+
# any workers up and running. If this is the case then we do nothing and
|
21
|
+
# let the worker pick up the jobs (and potentially hire more workers)
|
22
|
+
#
|
23
|
+
# If there are no workers, then we manually hire workers.
|
24
|
+
if ::Resque::Job.workers == 0
|
24
25
|
::Resque::Job.environment.hire
|
25
26
|
end
|
26
27
|
|
@@ -40,7 +40,7 @@ module ::Resque
|
|
40
40
|
# This means that there aren't any more jobs to process for any of the workers.
|
41
41
|
# If this is the case it'll command the current environment to fire all the hired workers
|
42
42
|
# and then immediately break out of this infinite loop.
|
43
|
-
if ::Resque::Job.jobs == 0
|
43
|
+
if (::Resque::Job.jobs + ::Resque::Job.working) == 0
|
44
44
|
::Resque::Job.environment.fire
|
45
45
|
break
|
46
46
|
else
|
data/spec/configuration_spec.rb
CHANGED
@@ -9,6 +9,7 @@ describe HireFire::Configuration do
|
|
9
9
|
|
10
10
|
configuration.environment.should == nil
|
11
11
|
configuration.max_workers.should == 1
|
12
|
+
configuration.min_workers.should == 0
|
12
13
|
configuration.job_worker_ratio.should == [
|
13
14
|
{ :jobs => 1, :workers => 1 },
|
14
15
|
{ :jobs => 25, :workers => 2 },
|
@@ -22,6 +23,7 @@ describe HireFire::Configuration do
|
|
22
23
|
HireFire.configure do |config|
|
23
24
|
config.environment = :noop
|
24
25
|
config.max_workers = 10
|
26
|
+
config.min_workers = 0
|
25
27
|
config.job_worker_ratio = [
|
26
28
|
{ :jobs => 1, :workers => 1 },
|
27
29
|
{ :jobs => 15, :workers => 2 },
|
@@ -35,6 +37,7 @@ describe HireFire::Configuration do
|
|
35
37
|
|
36
38
|
configuration.environment.should == :noop
|
37
39
|
configuration.max_workers.should == 10
|
40
|
+
configuration.min_workers.should == 0
|
38
41
|
configuration.job_worker_ratio.should == [
|
39
42
|
{ :jobs => 1, :workers => 1 },
|
40
43
|
{ :jobs => 15, :workers => 2 },
|
data/spec/environment_spec.rb
CHANGED
@@ -100,6 +100,16 @@ describe HireFire::Environment::Base do
|
|
100
100
|
base.expects(:workers).with(0).once
|
101
101
|
base.fire
|
102
102
|
end
|
103
|
+
|
104
|
+
it 'should set the workers to minimum workers when there arent any jobs' do
|
105
|
+
base.jobs = 0
|
106
|
+
base.workers = 10
|
107
|
+
base.stubs(:min_workers).returns(2)
|
108
|
+
|
109
|
+
HireFire::Logger.expects(:message).with('All queued jobs have been processed. Setting workers to 2.')
|
110
|
+
base.expects(:workers).with(2).once
|
111
|
+
base.fire
|
112
|
+
end
|
103
113
|
end
|
104
114
|
|
105
115
|
describe '#hire' do
|
@@ -228,6 +238,15 @@ describe HireFire::Environment::Base do
|
|
228
238
|
base.expects(:workers).with(5).never
|
229
239
|
base.hire
|
230
240
|
end
|
241
|
+
|
242
|
+
it 'should NEVER do API requests to Heroku if the workers query returns nil' do
|
243
|
+
base.jobs = 100
|
244
|
+
base.workers = nil
|
245
|
+
|
246
|
+
base.expects(:log_and_hire).never
|
247
|
+
base.expects(:fire).never
|
248
|
+
base.hire
|
249
|
+
end
|
231
250
|
end
|
232
251
|
|
233
252
|
describe 'the Lambda (functional) notation' do
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hirefire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 25
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 1
|
10
|
-
version: 0.1.1
|
5
|
+
version: 0.1.2
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Michael van Rooijen
|
@@ -15,7 +10,7 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-05-01 00:00:00 Z
|
19
14
|
dependencies:
|
20
15
|
- !ruby/object:Gem::Dependency
|
21
16
|
name: heroku
|
@@ -25,11 +20,6 @@ dependencies:
|
|
25
20
|
requirements:
|
26
21
|
- - ~>
|
27
22
|
- !ruby/object:Gem::Version
|
28
|
-
hash: 69
|
29
|
-
segments:
|
30
|
-
- 1
|
31
|
-
- 20
|
32
|
-
- 1
|
33
23
|
version: 1.20.1
|
34
24
|
type: :runtime
|
35
25
|
version_requirements: *id001
|
@@ -41,11 +31,6 @@ dependencies:
|
|
41
31
|
requirements:
|
42
32
|
- - ~>
|
43
33
|
- !ruby/object:Gem::Version
|
44
|
-
hash: 9
|
45
|
-
segments:
|
46
|
-
- 0
|
47
|
-
- 6
|
48
|
-
- 7
|
49
34
|
version: 0.6.7
|
50
35
|
type: :runtime
|
51
36
|
version_requirements: *id002
|
@@ -70,6 +55,7 @@ files:
|
|
70
55
|
- lib/hirefire.rb
|
71
56
|
- lib/hirefire/backend.rb
|
72
57
|
- lib/hirefire/backend/delayed_job/active_record.rb
|
58
|
+
- lib/hirefire/backend/delayed_job/active_record_2.rb
|
73
59
|
- lib/hirefire/backend/delayed_job/mongoid.rb
|
74
60
|
- lib/hirefire/backend/resque/redis.rb
|
75
61
|
- lib/hirefire/configuration.rb
|
@@ -105,25 +91,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
91
|
requirements:
|
106
92
|
- - ">="
|
107
93
|
- !ruby/object:Gem::Version
|
108
|
-
hash: 3
|
109
|
-
segments:
|
110
|
-
- 0
|
111
94
|
version: "0"
|
112
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
96
|
none: false
|
114
97
|
requirements:
|
115
98
|
- - ">="
|
116
99
|
- !ruby/object:Gem::Version
|
117
|
-
hash: 3
|
118
|
-
segments:
|
119
|
-
- 0
|
120
100
|
version: "0"
|
121
101
|
requirements: []
|
122
102
|
|
123
103
|
rubyforge_project:
|
124
|
-
rubygems_version: 1.7.
|
104
|
+
rubygems_version: 1.7.2
|
125
105
|
signing_key:
|
126
106
|
specification_version: 3
|
127
107
|
summary: HireFire automatically "hires" and "fires" (aka "scales") Delayed Job and Resque workers on Heroku.
|
128
108
|
test_files: []
|
129
109
|
|
110
|
+
has_rdoc:
|