feature request - when_ready() hook

Suraj Kurapati sunaku at gmail.com
Mon Mar 8 17:58:10 EST 2010


Hi Eric,

On Mon, Nov 30, 2009 at 3:47 PM, Suraj Kurapati wrote:
> from Capistrano, I send SIGUSR2 to the existing Unicorn master (which
> will become the old Unicorn master), wait 90 seconds, and then send
> SIGQUIT to the old Unicorn master. [...] The only thing I'm worried
> about is that I'll have to keep adjusting this timeout as the
> infrastructure my app depends upon becomes slower/faster.  A
> when_ready() hook would really do wonders for me

Inspired by your solution[1] to a recent question about forking, I
solved this problem by temporarily sneaking into the build_app! method
and killing the old Unicorn master after the Rails app has been built:

  before_fork do |server, worker|
    #
    # the following allows a new master process to incrementally
    # phase out the old master process with SIGTTOU to avoid a
    # thundering herd (especially in the "preload_app false" case)
    # when doing a transparent upgrade.  The last worker spawned
    # will then kill off the old master process with a SIGQUIT.
    #
    old_pid_file = server.config[:pid].to_s + '.oldbin'

    if File.exist? old_pid_file and
      server.pid != old_pid_file and
      worker.nr == server.worker_processes-1
    then
      #
      # wait until Rails app is built and ready to serve (we do this by
      # sneaking into Unicorn's build_app! method) by the last worker
      # process inside the new Unicorn before stopping old Unicorn
      #
      orig_meth_name = :build_app!
      orig_meth_impl = server.method(orig_meth_name)

      server_metaclass = class << server; self; end
      server_metaclass.class_eval do

        # replace Unicorn's method with our own sneaky version
        define_method orig_meth_name do

          # behave like Unicorn's original method
          orig_meth_impl.call

          # do our sneaky business! (kill the old Unicorn)
          begin
            Process.kill :QUIT, File.read(old_pid_file).to_i
          rescue Errno::ENOENT, Errno::ESRCH
            # ignore
          end

          # restore Unicorn's original method
          server_metaclass.class_eval do
            define_method orig_meth_name, orig_meth_impl
          end

        end
      end
    end
  end

Thanks for your help! :)

[1]: http://article.gmane.org/gmane.comp.lang.ruby.unicorn.general/425


More information about the mongrel-unicorn mailing list