hirefire 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|