hirefire 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # HireFire
5
+ # This is a HireFire modified version of
6
+ # the official Resque::Worker class
7
+ module ::Resque
8
+ class Worker
9
+ def work(interval = 5.0, &block)
10
+ interval = Float(interval)
11
+ $0 = "resque: Starting"
12
+ startup
13
+
14
+ loop do
15
+ break if shutdown?
16
+ ::Resque::Job.environment.hire
17
+
18
+ if not @paused and job = reserve
19
+ log "got: #{job.inspect}"
20
+ run_hook :before_fork, job
21
+ working_on job
22
+
23
+ if @child = fork
24
+ rand # Reseeding
25
+ procline "Forked #{@child} at #{Time.now.to_i}"
26
+ Process.wait
27
+ else
28
+ procline "Processing #{job.queue} since #{Time.now.to_i}"
29
+ perform(job, &block)
30
+ exit! unless @cant_fork
31
+ end
32
+
33
+ done_working
34
+ @child = nil
35
+ else
36
+
37
+ ##
38
+ # HireFire Hook
39
+ # After the last job in the queue finishes processing, Resque::Job.jobs will return 0.
40
+ # This means that there aren't any more jobs to process for any of the workers.
41
+ # If this is the case it'll command the current environment to fire all the hired workers
42
+ # and then immediately break out of this infinite loop.
43
+ if ::Resque::Job.jobs == 0
44
+ ::Resque::Job.environment.fire
45
+ break
46
+ else
47
+ sleep(interval)
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ ensure
54
+ unregister_worker
55
+ end
56
+ end
57
+ end
@@ -44,4 +44,24 @@ describe HireFire::Configuration do
44
44
  ]
45
45
  end
46
46
 
47
+ it 'should allow functional syntax' do
48
+ ratio = [
49
+ { :when => lambda {|jobs| jobs < 15 }, :workers => 1 },
50
+ { :when => lambda {|jobs| jobs < 35 }, :workers => 2 },
51
+ { :when => lambda {|jobs| jobs < 60 }, :workers => 3 },
52
+ { :when => lambda {|jobs| jobs < 80 }, :workers => 4 }
53
+ ]
54
+
55
+ HireFire.configure do |config|
56
+ config.environment = :noop
57
+ config.max_workers = 10
58
+ config.job_worker_ratio = ratio
59
+ end
60
+
61
+ configuration = HireFire.configuration
62
+
63
+ configuration.environment.should == :noop
64
+ configuration.max_workers.should == 10
65
+ configuration.job_worker_ratio.should == ratio
66
+ end
47
67
  end
@@ -0,0 +1,359 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../spec_helper', __FILE__)
4
+
5
+ module HireFire
6
+ module Backend
7
+ ##
8
+ # Stub out backend interface inclusion
9
+ # since it's irrelevant for these tests
10
+ def self.included(base)
11
+ base.send(:include, Environment::Stub)
12
+ end
13
+ end
14
+
15
+ module Environment
16
+ module Stub
17
+ ##
18
+ # Stubbed out since this normally comes from
19
+ # a sub class like HireFire::Environment::Heroku or
20
+ # HireFire::Environment::Local
21
+ def workers(amount = nil)
22
+ if amount.nil?
23
+ @_workers ||= 0
24
+ return @_workers
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Allows the specs to stub the workers count
30
+ # and return the desired amount
31
+ def workers=(amount)
32
+ @_workers = amount
33
+ self.stubs(:workers).with.returns(amount)
34
+ end
35
+
36
+ ##
37
+ # Returns the amount of jobs
38
+ # Defaults to: 0
39
+ def jobs
40
+ @_jobs ||= 0
41
+ end
42
+
43
+ ##
44
+ # Allows the specs to stub the queued job count
45
+ # and return the desired amount
46
+ def jobs=(amount)
47
+ @_jobs = amount
48
+ self.stubs(:jobs).returns(amount)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ describe HireFire::Environment::Base do
55
+
56
+ let(:base) { HireFire::Environment::Base.new }
57
+
58
+ describe 'testing the test setup' do
59
+ it 'should default the queued job count to 0 for these specs' do
60
+ base.jobs.should == 0
61
+ end
62
+
63
+ it 'should set the queued job count to 10' do
64
+ base.jobs = 10
65
+ base.jobs.should == 10
66
+ end
67
+
68
+ it 'should have zero workers by default' do
69
+ base.workers.should == 0
70
+ end
71
+
72
+ it 'should set the amount of workers to 10' do
73
+ base.workers = 10
74
+ base.workers.should == 10
75
+ end
76
+ end
77
+
78
+ describe '#fire' do
79
+ it 'should not fire any workers when there are still jobs in the queue' do
80
+ base.jobs = 1
81
+ base.workers = 1
82
+
83
+ base.expects(:workers).with(0).never
84
+ base.fire
85
+ end
86
+
87
+ it 'should not fire any workers if there arent any workers' do
88
+ base.jobs = 1
89
+ base.workers = 0
90
+
91
+ base.expects(:workers).with(0).never
92
+ base.fire
93
+ end
94
+
95
+ it 'should fire all workers when there arent any jobs' do
96
+ base.jobs = 0
97
+ base.workers = 1
98
+
99
+ HireFire::Logger.expects(:message).with('All queued jobs have been processed. Firing all workers.')
100
+ base.expects(:workers).with(0).once
101
+ base.fire
102
+ end
103
+ end
104
+
105
+ describe '#hire' do
106
+ describe 'the standard notation' do
107
+ before do
108
+ base.stubs(:max_workers).returns(5)
109
+ base.stubs(:ratio).returns([
110
+ { :jobs => 1, :workers => 1 },
111
+ { :jobs => 15, :workers => 2 },
112
+ { :jobs => 30, :workers => 3 },
113
+ { :jobs => 60, :workers => 4 },
114
+ { :jobs => 90, :workers => 5 }
115
+ ])
116
+ end
117
+
118
+ it 'should request 1 worker' do
119
+ base.jobs = 1
120
+ base.workers = 0
121
+
122
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 1 in total.')
123
+ base.expects(:workers).with(1).once
124
+ base.hire
125
+ end
126
+
127
+ it 'should not request 1 worker, since there already is one worker running' do
128
+ base.jobs = 5
129
+ base.workers = 1
130
+
131
+ base.expects(:workers).with(1).never
132
+ base.hire
133
+ end
134
+
135
+ it 'should request 2 workers' do
136
+ base.jobs = 15
137
+ base.workers = 0
138
+
139
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 2 in total.')
140
+ base.expects(:workers).with(2).once
141
+ base.hire
142
+ end
143
+
144
+ it 'should request 2 workers' do
145
+ base.jobs = 20
146
+ base.workers = 1
147
+
148
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 2 in total.')
149
+ base.expects(:workers).with(2).once
150
+ base.hire
151
+ end
152
+
153
+ it 'should not request 2 workers since we already have 2' do
154
+ base.jobs = 25
155
+ base.workers = 2
156
+
157
+ base.expects(:workers).with(2).never
158
+ base.hire
159
+ end
160
+
161
+ it 'should NEVER lower the worker amount from the #hire method' do
162
+ base.jobs = 25 # simulate that 5 jobs are already processed (30 - 5)
163
+ base.workers = 3 # and 3 workers are hired
164
+
165
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 2 in total.').never
166
+ base.expects(:workers).with(2).never
167
+ base.hire
168
+ end
169
+
170
+ it 'should NEVER hire more workers than the #max_workers' do
171
+ base.jobs = 100
172
+ base.workers = 0
173
+
174
+ base.stubs(:max_workers).returns(3) # set the max_workers = 3
175
+
176
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 3 in total.').once
177
+ base.expects(:workers).with(3).once
178
+ base.hire
179
+ end
180
+
181
+ it 'should not hire 5 workers even if defined in the job/ratio, when the limit is 3, it should hire 3 max' do
182
+ base.jobs = 100
183
+ base.workers = 0
184
+
185
+ base.stubs(:max_workers).returns(3) # set the max_workers = 3
186
+ base.stubs(:ratio).returns([
187
+ { :jobs => 5, :workers => 5 }
188
+ ])
189
+
190
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 3 in total.').once
191
+ base.expects(:workers).with(3).once
192
+ base.hire
193
+ end
194
+
195
+ it 'should not hire (or invoke) any more workers since the max amount allowed is already running' do
196
+ base.jobs = 100
197
+ base.workers = 3
198
+
199
+ base.stubs(:max_workers).returns(3) # set the max_workers = 3
200
+ base.stubs(:ratio).returns([
201
+ { :jobs => 5, :workers => 5 }
202
+ ])
203
+
204
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 3 in total.').never
205
+ base.expects(:workers).with(3).never
206
+ base.hire
207
+ end
208
+
209
+ it 'the max_workers option can only "limit" the amount of max_workers when used in the "Standard Notation"' do
210
+ base.jobs = 100
211
+ base.workers = 0
212
+
213
+ base.stubs(:max_workers).returns(10) # set the max_workers = 10
214
+ base.stubs(:ratio).returns([
215
+ { :jobs => 5, :workers => 5 }
216
+ ])
217
+
218
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 5 in total.').once
219
+ base.expects(:workers).with(5).once
220
+ base.hire
221
+ end
222
+
223
+ it 'should NEVER do API requests to Heroku if the max_workers are already running' do
224
+ base.jobs = 100
225
+ base.workers = 5
226
+
227
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 5 in total.').never
228
+ base.expects(:workers).with(5).never
229
+ base.hire
230
+ end
231
+ end
232
+
233
+ describe 'the Lambda (functional) notation' do
234
+ before do
235
+ base.stubs(:max_workers).returns(5)
236
+ base.stubs(:ratio).returns([
237
+ { :when => lambda {|jobs| jobs < 15 }, :workers => 1 },
238
+ { :when => lambda {|jobs| jobs < 30 }, :workers => 2 },
239
+ { :when => lambda {|jobs| jobs < 60 }, :workers => 3 },
240
+ { :when => lambda {|jobs| jobs < 90 }, :workers => 4 }
241
+ ])
242
+ end
243
+
244
+ it 'should request 1 worker' do
245
+ base.jobs = 1
246
+ base.workers = 0
247
+
248
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 1 in total.')
249
+ base.expects(:workers).with(1).once
250
+ base.hire
251
+ end
252
+
253
+ it 'should not request 1 worker, since there already is one worker running' do
254
+ base.jobs = 5
255
+ base.workers = 1
256
+
257
+ base.expects(:workers).with(1).never
258
+ base.hire
259
+ end
260
+
261
+ it 'should request 2 workers' do
262
+ base.jobs = 15
263
+ base.workers = 0
264
+
265
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 2 in total.')
266
+ base.expects(:workers).with(2).once
267
+ base.hire
268
+ end
269
+
270
+ it 'should request 2 workers' do
271
+ base.jobs = 20
272
+ base.workers = 1
273
+
274
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 2 in total.')
275
+ base.expects(:workers).with(2).once
276
+ base.hire
277
+ end
278
+
279
+ it 'should not request 2 workers since we already have 2' do
280
+ base.jobs = 25
281
+ base.workers = 2
282
+
283
+ base.expects(:workers).with(2).never
284
+ base.hire
285
+ end
286
+
287
+ it 'should NEVER lower the worker amount from the #hire method' do
288
+ base.jobs = 25 # simulate that 5 jobs are already processed (30 - 5)
289
+ base.workers = 3 # and 3 workers are hired
290
+
291
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 2 in total.').never
292
+ base.expects(:workers).with(2).never
293
+ base.hire
294
+ end
295
+
296
+ it 'should NEVER hire more workers than the #max_workers' do
297
+ base.jobs = 100
298
+ base.workers = 0
299
+
300
+ base.stubs(:max_workers).returns(3) # set the max_workers = 3
301
+
302
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 3 in total.').once
303
+ base.expects(:workers).with(3).once
304
+ base.hire
305
+ end
306
+
307
+ it 'should not hire 5 workers even if defined in the job/ratio, when the limit is 3, it should hire 3 max' do
308
+ base.jobs = 100
309
+ base.workers = 0
310
+
311
+ base.stubs(:max_workers).returns(3) # set the max_workers = 3
312
+ base.stubs(:ratio).returns([
313
+ { :when => lambda { |jobs| jobs < 5 }, :workers => 5 }
314
+ ])
315
+
316
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 3 in total.').once
317
+ base.expects(:workers).with(3).once
318
+ base.hire
319
+ end
320
+
321
+ it 'should not hire (or invoke) any more workers since the max amount allowed is already running' do
322
+ base.jobs = 100
323
+ base.workers = 3
324
+
325
+ base.stubs(:max_workers).returns(3) # set the max_workers = 3
326
+ base.stubs(:ratio).returns([
327
+ { :when => lambda { |jobs| jobs < 5 }, :workers => 5 }
328
+ ])
329
+
330
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 3 in total.').never
331
+ base.expects(:workers).with(3).never
332
+ base.hire
333
+ end
334
+
335
+ it 'the max_workers option can only "limit" the amount of max_workers when used in the "Standard Notation"' do
336
+ base.jobs = 100
337
+ base.workers = 0
338
+
339
+ base.stubs(:max_workers).returns(10) # set the max_workers = 10
340
+ base.stubs(:ratio).returns([
341
+ { :when => lambda { |jobs| jobs < 5 }, :workers => 5 }
342
+ ])
343
+
344
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 10 in total.').once
345
+ base.expects(:workers).with(10).once
346
+ base.hire
347
+ end
348
+
349
+ it 'should NEVER do API requests to Heroku if the max_workers are already running' do
350
+ base.jobs = 100
351
+ base.workers = 5
352
+
353
+ HireFire::Logger.expects(:message).with('Hiring more workers so we have 5 in total.').never
354
+ base.expects(:workers).with(5).never
355
+ base.hire
356
+ end
357
+ end
358
+ end
359
+ end
metadata CHANGED
@@ -1,8 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hirefire
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 25
4
5
  prerelease:
5
- version: 0.1.0
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
6
11
  platform: ruby
7
12
  authors:
8
13
  - Michael van Rooijen
@@ -10,7 +15,7 @@ autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
17
 
13
- date: 2011-04-10 00:00:00 Z
18
+ date: 2011-04-15 00:00:00 Z
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: heroku
@@ -20,6 +25,11 @@ dependencies:
20
25
  requirements:
21
26
  - - ~>
22
27
  - !ruby/object:Gem::Version
28
+ hash: 69
29
+ segments:
30
+ - 1
31
+ - 20
32
+ - 1
23
33
  version: 1.20.1
24
34
  type: :runtime
25
35
  version_requirements: *id001
@@ -31,10 +41,15 @@ dependencies:
31
41
  requirements:
32
42
  - - ~>
33
43
  - !ruby/object:Gem::Version
44
+ hash: 9
45
+ segments:
46
+ - 0
47
+ - 6
48
+ - 7
34
49
  version: 0.6.7
35
50
  type: :runtime
36
51
  version_requirements: *id002
37
- description: " HireFire automatically \"hires\" and \"fires\" (aka \"scales\") Delayed Job workers on Heroku.\n When there are no queue jobs, HireFire will fire (shut down) all workers. If there are\n queued jobs, then it'll hire (spin up) workers. The amount of workers that get hired\n depends on the amount of queued jobs (the ratio can be configured by you). HireFire\n is great for both high, mid and low traffic applications. It can save you a lot of\n money by only hiring workers when there are pending jobs, and then firing them again\n once all the jobs have been processed. It's also capable to dramatically reducing\n processing time by automatically hiring more workers when the queue size increases.\n"
52
+ description: HireFire automatically "hires" and "fires" (aka "scales") Delayed Job and Resque workers on Heroku. When there are no queue jobs, HireFire will fire (shut down) all workers. If there are queued jobs, then it'll hire (spin up) workers. The amount of workers that get hired depends on the amount of queued jobs (the ratio can be configured by you). HireFire is great for both high, mid and low traffic applications. It can save you a lot of money by only hiring workers when there are pending jobs, and then firing them again once all the jobs have been processed. It's also capable to dramatically reducing processing time by automatically hiring more workers when the queue size increases.
38
53
  email: meskyanichi@gmail.com
39
54
  executables: []
40
55
 
@@ -54,10 +69,10 @@ files:
54
69
  - hirefire.gemspec
55
70
  - lib/hirefire.rb
56
71
  - lib/hirefire/backend.rb
57
- - lib/hirefire/backend/active_record.rb
58
- - lib/hirefire/backend/mongoid.rb
72
+ - lib/hirefire/backend/delayed_job/active_record.rb
73
+ - lib/hirefire/backend/delayed_job/mongoid.rb
74
+ - lib/hirefire/backend/resque/redis.rb
59
75
  - lib/hirefire/configuration.rb
60
- - lib/hirefire/delayed_job_extension.rb
61
76
  - lib/hirefire/environment.rb
62
77
  - lib/hirefire/environment/base.rb
63
78
  - lib/hirefire/environment/heroku.rb
@@ -67,7 +82,14 @@ files:
67
82
  - lib/hirefire/logger.rb
68
83
  - lib/hirefire/railtie.rb
69
84
  - lib/hirefire/version.rb
85
+ - lib/hirefire/workers/delayed_job.rb
86
+ - lib/hirefire/workers/delayed_job/worker.rb
87
+ - lib/hirefire/workers/resque.rb
88
+ - lib/hirefire/workers/resque/job.rb
89
+ - lib/hirefire/workers/resque/tasks.rb
90
+ - lib/hirefire/workers/resque/worker.rb
70
91
  - spec/configuration_spec.rb
92
+ - spec/environment_spec.rb
71
93
  - spec/logger_spec.rb
72
94
  - spec/spec_helper.rb
73
95
  homepage: http://rubygems.org/gems/hirefire
@@ -83,20 +105,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
105
  requirements:
84
106
  - - ">="
85
107
  - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
86
111
  version: "0"
87
112
  required_rubygems_version: !ruby/object:Gem::Requirement
88
113
  none: false
89
114
  requirements:
90
115
  - - ">="
91
116
  - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
92
120
  version: "0"
93
121
  requirements: []
94
122
 
95
123
  rubyforge_project:
96
- rubygems_version: 1.7.2
124
+ rubygems_version: 1.7.1
97
125
  signing_key:
98
126
  specification_version: 3
99
- summary: HireFire automatically "hires" and "fires" (aka "scales") Delayed Job workers on Heroku.
127
+ summary: HireFire automatically "hires" and "fires" (aka "scales") Delayed Job and Resque workers on Heroku.
100
128
  test_files: []
101
129
 
102
- has_rdoc: