8
task :restart_unicorn, :except => { :no_release => true } do
  run "#{try_sudo} kill -s USR2 $(cat /var/www/app_name/shared/pids/unicorn.pid)"
end

サーバー上で行うsudo kill -s USR2 $(cat /var/www/app_name/shared/pids/unicorn.pid)と、新しいユニコーン マスターが作成され、古いマスターが(old)その名前に追加されます。古いものは決して強制終了されませんが、自分で強制終了したとしても、新しいユニコーン インスタンスはデプロイ前の古いコードを表示したままです。新しいインスタンスの作成時間は古いものと同じです。まるで複製されているかのようです。インスタンスを停止して再起動すると機能しますが、ダウンタイムなしでデプロイできるようにしたいと考えています。

どんな助けでも大歓迎です。

編集

sugest Ilya O. に従って、これを行う capistrano タスクを作成しました。

old_pid = get_pid('/var/www/appname/shared/pids/unicorn.pid')
run "#{try_sudo} kill -s SIGUSR2 $(cat /var/www/appname/shared/pids/unicorn.pid)"
/var/www/app/current/tmp/pids/unicorn.pid)"
run "#{try_sudo} kill -s SIGWINCH #{old_pid}"

これにより、pid で SIGUSR2 が実行され、古いユニコーン プロセスが強制終了されます。問題は、すべてのアプリケーション サーバーが最近デプロイされたコードに更新されないことです。このタスクは、古いユニコーン環境を新しいプロセスにコピーしているように見えます。単純にマスター プロセスを強制終了してから、Unicorn を新たに起動すると問題なく動作しますが、その後 1 分ほどでリクエストが破棄されます。

4

3 に答える 3

6

preload_appUnicorn構成でtrueに設定しましたか?その場合は、新しいプロセスが起動して実行された後、SIGUSR2を送信してからSIGQUITを元のマスタープロセスに送信する必要があります。

また、元のマスタープロセスが停止したが、子がまだリクエストを処理している可能性もあります。SIGUSR2を送信してみてください。新しいマスタープロセスが生成されたら、SIGWINCHを(古いマスターに)送信して古いユニコーンの子プロセスを強制終了し、次に古いマスタープロセスでSIGQUITを送信します。これで、リクエストを処理する「新しい」ユニコーンプロセスのみが作成されます。

編集:SIGWINCHの代わりにSIGQUITを実行してみてください。古いプロセスは、SIGWINCHの後にワーカーを生成している可能性があると思います。

于 2012-11-27T06:42:46.807 に答える
3

なぜカピストラーノにすべての作業を入れているのかわかりませんが、通常はカピストラーノで次のようなもので十分です:

set :unicorn_pid, "unicorn.my_website.pid"

desc "Zero-downtime restart of Unicorn"
task :restart, roles: :app do
  if remote_file_exists?("/tmp/#{unicorn_pid}")
    puts "Killing /tmp/#{unicorn_pid}"
    run "kill -s USR2 `cat /tmp/#{unicorn_pid}`"
  else
    run "cd #{current_path} ; RAILS_ENV=#{rails_env} bundle exec unicorn_rails -c #{unicorn_config} -D"
  end
end

そして、古いユニコーンプロセスを強制終了するための実際のコードは、実際にはユニコーン構成にあります

# config/unicorn.rb

# Set environment to development unless something else is specified
env = ENV["RAILS_ENV"] || "production"

# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete documentation.
worker_processes 2 # amount of unicorn workers to spin up

APP_PATH = "/u/apps/my_website/current"

listen "/tmp/my_website.socket"

preload_app true

timeout 30         # restarts workers that hang for 30 seconds

pid "/tmp/unicorn.my_website.pid"

# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path APP_PATH + "/log/unicorn.stderr.log"
stdout_path APP_PATH + "/log/unicorn.stdout.log"

if env == "production"
  # Help ensure your application will always spawn in the symlinked
  # "current" directory that Capistrano sets up.
  working_directory APP_PATH

  # feel free to point this anywhere accessible on the filesystem
  user 'deploy', 'deploy' # 'user', 'group'
  shared_path = "/u/apps/my_website/shared"

  stderr_path "#{shared_path}/log/unicorn.stderr.log"
  stdout_path "#{shared_path}/log/unicorn.stdout.log"
end

before_fork do |server, worker|
  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end


  # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
  # immediately start loading up a new version of itself (loaded with a new
  # version of our app). When this new Unicorn is completely loaded
  # it will begin spawning workers. The first worker spawned will check to
  # see if an .oldbin pidfile exists. If so, this means we've just booted up
  # a new Unicorn and need to tell the old one that it can now die. To do so
  # we send it a QUIT.
  #
  # This enables 0 downtime deploys.
  old_pid = "/tmp/unicorn.my_website.pid.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

after_fork do |server, worker|

  # Unicorn master loads the app then forks off workers - because of the way
  # Unix forking works, we need to make sure we aren't using any of the parent's
  # sockets, e.g. db connection (since "preload_app true")
  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
  end

  # if preload_app is true, then you may also want to check and
  # restart any other shared sockets/descriptors such as Memcached,
  # and Redis.  TokyoCabinet file handles are safe to reuse
  # between any number of forked children (assuming your kernel
  # correctly implements pread()/pwrite() system calls)
end

私はほとんどの場合そのセットアップを使用し、私のアプリケーションは問題なくリロードされます。ほとんどがデフォルト構成であるため、おそらくすでにすべてのものを持っていますが、何か不足している場合は試してみてください;)

于 2012-12-05T09:56:10.383 に答える
2

Unicorn の連中は、このための公開された init.d スクリプトを持っています。おそらく、それをシステムに追加して使用する必要があります。

unicorn を再起動するには、再起動とアップグレードの 2 つの方法があります。

このスクリプトを /etc/init.d/unicorn に個人的に追加し、この実行可能ファイルを設定するsudo service unicorn upgradeと、カピストラーノ レシピで使用できるようになります。

初期化スクリプト: http://unicorn.bogomips.org/examples/init.sh

于 2012-11-29T23:27:57.020 に答える