Skip to content

Commit

Permalink
Allow to mark workers as fork unsafe
Browse files Browse the repository at this point in the history
When some part of an application is hard or impossible to make
fork-safe, but rarely called, it's possible to simply mark the worker
as fork unsafe, and rely on its siblings to fork the next generation.

In the eventually where all the workers end up marked fork unsafe,
no new generation will be spawned, unless of course one of the unsafe
workers die and is replaced by a fresh one.

So this is only meant as a workaround for infrequently called things.
  • Loading branch information
byroot committed Jul 24, 2023
1 parent ef4bea0 commit d5ac0f0
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/pitchfork/http_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ def worker_loop(worker)
# timeout so we can update .deadline and keep parent from SIGKILL-ing us
worker.update_deadline(@timeout)

if @refork_condition && !worker.outdated?
if @refork_condition && Info.fork_safe? && !worker.outdated?
if @refork_condition.met?(worker, logger)
if spawn_mold(worker.generation)
logger.info("Refork condition met, promoting ourselves")
Expand Down
9 changes: 9 additions & 0 deletions lib/pitchfork/info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,19 @@
module Pitchfork
module Info
@workers_count = 0
@fork_safe = true

class << self
attr_accessor :workers_count

def fork_safe?
@fork_safe
end

def no_longer_fork_safe!
@fork_safe = false
end

def live_workers_count
now = Pitchfork.time_now(true)
(0...workers_count).count do |nr|
Expand Down
6 changes: 6 additions & 0 deletions test/integration/fork_unsafe.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use Rack::ContentLength
use Rack::ContentType, "text/plain"
run lambda { |env|
Pitchfork::Info.no_longer_fork_safe!
[ 200, {}, [ env.inspect << "\n" ] ]
}
22 changes: 22 additions & 0 deletions test/integration/test_reforking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ def test_reforking_broken_after_mold_fork_hook
assert_clean_shutdown(pid)
end

def test_fork_unsafe
addr, port = unused_port

pid = spawn_server(app: File.join(ROOT, "test/integration/fork_unsafe.ru"), config: <<~CONFIG)
listen "#{addr}:#{port}"
worker_processes 2
refork_after [5, 5]
CONFIG

assert_healthy("http://#{addr}:#{port}")
assert_stderr "worker=0 gen=0 ready"
assert_stderr "worker=1 gen=0 ready"

20.times do
assert_equal true, healthy?("http://#{addr}:#{port}")
end

refute_match("Refork condition met, promoting ourselves", read_stderr)

assert_clean_shutdown(pid)
end

def test_reforking_on_USR2
addr, port = unused_port

Expand Down

0 comments on commit d5ac0f0

Please sign in to comment.