Skip to content

Commit 1f5a5ae

Browse files
committed
Merge pull request resque#672 from kjwierenga/feature/conditional_fork_hooks
Don't invoke :before_fork and :after_fork hooks when not forking - fixes fd leak when used with NewRelic Conflicts: lib/resque/worker.rb test/worker_test.rb
1 parent e3af893 commit 1f5a5ae

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

lib/resque/worker.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,9 @@ def work(interval = 5.0, &block)
137137
if job = reserve(interval)
138138
log "got: #{job.inspect}"
139139
job.worker = self
140-
run_hook :before_fork, job
141140
working_on job
142141

143-
if @child = fork
142+
if @child = fork(job)
144143
srand # Reseeding
145144
procline "Forked #{@child} at #{Time.now.to_i}"
146145
begin
@@ -149,11 +148,11 @@ def work(interval = 5.0, &block)
149148
nil
150149
end
151150
else
152-
unregister_signal_handlers if !@cant_fork
151+
unregister_signal_handlers if will_fork?
153152
procline "Processing #{job.queue} since #{Time.now.to_i}"
154153
reconnect
155154
perform(job, &block)
156-
exit! unless @cant_fork
155+
exit! if will_fork?
157156
end
158157

159158
done_working
@@ -185,7 +184,7 @@ def process(job = nil, &block)
185184
# Processes a given job in the child.
186185
def perform(job)
187186
begin
188-
run_hook :after_fork, job
187+
run_hook :after_fork, job unless @cant_fork
189188
job.perform
190189
rescue Object => e
191190
log "#{job.inspect} failed: #{e.inspect}"
@@ -253,15 +252,17 @@ def queues
253252

254253
# Not every platform supports fork. Here we do our magic to
255254
# determine if yours does.
256-
def fork
257-
@cant_fork = true if $TESTING
258-
255+
def fork(job)
259256
return if @cant_fork
257+
258+
# Only run before_fork hooks if we're actually going to fork
259+
# (after checking @cant_fork)
260+
run_hook :before_fork, job
260261

261262
begin
262263
# IronRuby doesn't support `Kernel.fork` yet
263264
if Kernel.respond_to?(:fork)
264-
Kernel.fork
265+
Kernel.fork if will_fork?
265266
else
266267
raise NotImplementedError
267268
end
@@ -519,6 +520,10 @@ def working?
519520
def idle?
520521
state == :idle
521522
end
523+
524+
def will_fork?
525+
!(@cant_fork || $TESTING)
526+
end
522527

523528
# Returns a symbol representing the current worker state,
524529
# which can be either :working or :idle

test/worker_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,19 @@ def self.perform
449449
workerA.work(0)
450450
assert $BEFORE_FORK_CALLED
451451
end
452+
453+
test "Will not call a before_fork hook when the worker can't fork" do
454+
Resque.redis.flushall
455+
$BEFORE_FORK_CALLED = false
456+
Resque.before_fork = Proc.new { $BEFORE_FORK_CALLED = true }
457+
workerA = Resque::Worker.new(:jobs)
458+
workerA.cant_fork = true
459+
460+
assert !$BEFORE_FORK_CALLED, "before_fork should not have been called before job runs"
461+
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
462+
workerA.work(0)
463+
assert !$BEFORE_FORK_CALLED, "before_fork should not have been called after job runs"
464+
end
452465

453466
it "very verbose works in the afternoon" do
454467
begin
@@ -480,6 +493,19 @@ def self.perform
480493
assert $AFTER_FORK_CALLED
481494
end
482495

496+
it "Will not call an after_fork hook when the worker can't fork" do
497+
Resque.redis.flushall
498+
$AFTER_FORK_CALLED = false
499+
Resque.after_fork = Proc.new { $AFTER_FORK_CALLED = true }
500+
workerA = Resque::Worker.new(:jobs)
501+
workerA.cant_fork = true
502+
503+
assert !$AFTER_FORK_CALLED
504+
Resque::Job.create(:jobs, SomeJob, 20, '/tmp')
505+
workerA.work(0)
506+
assert !$AFTER_FORK_CALLED
507+
end
508+
483509
it "returns PID of running process" do
484510
assert_equal @worker.to_s.split(":")[1].to_i, @worker.pid
485511
end

0 commit comments

Comments
 (0)