FIX: Ensure we dispose of MiniRacer::Context before forking daemons (#28361)

This commit updates `Demon::Base#start` to call `Discourse.before_fork`
before forking. According to the docs in `mini_racer`, we need to
"Dispose manually of all MiniRacer::Context objects prior to forking".

This commit is motivated by a segmentation fault which we are seeing in
production when killing a daemon process. Backtrace of the core dump
includes traces of `mini_racer` so we think this is the cause. Note that
we are not 100% sure if this will fix the issue.
This commit is contained in:
Alan Guo Xiang Tan 2024-08-14 12:45:34 +08:00 committed by GitHub
parent e82e255531
commit 10ff0ee0cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 9 deletions

View File

@ -64,15 +64,7 @@ initialized = false
before_fork do |server, worker| before_fork do |server, worker|
unless initialized unless initialized
Discourse.preload_rails! Discourse.preload_rails!
Discourse.before_fork
# V8 does not support forking, make sure all contexts are disposed
ObjectSpace.each_object(MiniRacer::Context) { |c| c.dispose }
# get rid of rubbish so we don't share it
# longer term we will use compact! here
GC.start
GC.start
GC.start
initialized = true initialized = true

View File

@ -154,6 +154,8 @@ class Demon::Base
end end
def run def run
Discourse.before_fork if defined?(Discourse)
@pid = @pid =
fork do fork do
Process.setproctitle("discourse #{self.class.prefix}") Process.setproctitle("discourse #{self.class.prefix}")
@ -161,6 +163,7 @@ class Demon::Base
establish_app establish_app
after_fork after_fork
end end
write_pid_file write_pid_file
end end

View File

@ -896,6 +896,20 @@ module Discourse
"/site/read-only" "/site/read-only"
end end
# all forking servers must call this
# before forking, otherwise the forked process might
# be in a bad state
def self.before_fork
# V8 does not support forking, make sure all contexts are disposed
ObjectSpace.each_object(MiniRacer::Context) { |c| c.dispose }
# get rid of rubbish so we don't share it
# longer term we will use compact! here
GC.start
GC.start
GC.start
end
# all forking servers must call this # all forking servers must call this
# after fork, otherwise Discourse will be # after fork, otherwise Discourse will be
# in a bad state # in a bad state