部署 解决 mina unicorn restart 不生效的问题

luolinae86 · November 27, 2018 · Last by luolinae86 replied at November 27, 2018 · 6421 hits

问题描述

目前的项目,基于 nginx + unicorn + mina 进行部署

其中,mina 无缝重启 unicorn 是用的 mina-unicorn 这个 gem

https://github.com/scarfacedeb/mina-unicorn

具体的部署方式,可以参考之前写过的一篇部署帖子

https://ruby-china.org/topics/26661

但有时,发现成功执行了 mina deploy,代码更新到了远程服务器,unicorn 进程重启过,unicorn 的 pid 也改变了,但新增加的功能却没有生效。

查阅了论坛,也看到之前已经有用户遇到了相同的问题,因此,得想办法解决。

问题解决

mina-unicorn 重启 unicorn 的命令 unicorn:restart 源码在此

# 作者也注释过了,借鉴的 capistrano-unicorn 
# Ported from: https://github.com/sosedoff/capistrano-unicorn/blob/master/lib/capistrano-unicorn/utility.rb

https://github.com/scarfacedeb/mina-unicorn/blob/master/lib/mina/unicorn/utility.rb

查看了源码,没有发现太多的端倪,但思路是先停 unicorn,再启动 unicorn 因此,自己重写了 config/deployer.rb 中的 unicorn:restart 部分

增加了 代码如下

namespace :unicorn do
  set :unicorn_pid, "#{deploy_to}/tmp/pids/unicorn.pid"

  desc "Start Unicorn"
  task :start => :environment do
    queue 'echo "-----> Start Unicorn"'
    queue! %{
      cd #{deploy_to}/#{current_path} && bundle exec unicorn_rails -c config/unicorn.rb -E production -D
    }
  end

  desc "Stop Unicorn"
  task :stop do
    queue 'echo "-----> Stop Unicorn"'
    queue! %{
      kill -QUIT `cat "#{unicorn_pid}"` && rm -rf "#{unicorn_pid}" && echo "Stop Ok" && exit 0
      echo >&2 "Not running"
    }
  end

  desc "Restart unicorn"
  task :restart => :environment do
    invoke 'unicorn:stop'
    invoke 'unicorn:start'
  end
end

config/deployer.rb 文件更新

使用上面的代码之后,就可以不用再引用 mina/unicorn这个文件,下面是整个config/deployer.rb配置文件,供参考

require 'mina/bundler'
require 'mina/rails'
require 'mina/git'
require 'mina/rvm'
#require 'mina/unicorn' 不再需要了
require "mina_sidekiq/tasks"

set :bundle_gemfile,"#{deploy_to}/#{current_path}/Gemfile"
set :deploy_to, '/data/project/your_project'
set :bundle_gemfile,"#{deploy_to}/#{current_path}/Gemfile"

#设置git地址及分支
set :repository, 'your_git.git'
set :branch, 'develop'
set :shared_paths, ['config/database.yml', 'config/local_env.yml']

#设置sidekiq unicorn 的进程保存地址
set :sidekiq_pid, "#{deploy_to}/tmp/pids/sidekiq.pid"
set :unicorn_pid, "#{deploy_to}/tmp/pids/unicorn.pid"

task :environment do
  invoke :'rvm:use[ruby-ruby-2.3.0]'
end

task :setup => :environment do
  # unicorn and sidekiq needs a place to store its pid file
  queue! %[mkdir -p "#{deploy_to}/tmp/sockets/"]
  queue! %[mkdir -p "#{deploy_to}/tmp/pids/"]

  queue! %[mkdir -p "#{deploy_to}/#{shared_path}/log"]
  queue! %[mkdir -p "#{deploy_to}/#{shared_path}/config"]

  queue! %[touch "#{deploy_to}/#{shared_path}/config/local_env.yml"]
  queue! %[touch "#{deploy_to}/#{shared_path}/config/database.yml"]
  queue  %[echo "-----> Be sure to edit '#{deploy_to}/#{shared_path}/config/database.yml','local_env.yml'."]

  queue %[
    repo_host=`echo $repo | sed -e 's/.*@//g' -e 's/:.*//g'` &&
    repo_port=`echo $repo | grep -o ':[0-9]*' | sed -e 's/://g'` &&
    if [ -z "${repo_port}" ]; then repo_port=22; fi ]
end

task :development do
  set :domain, development_ip
  set :user, user_name
  set :port, port
  set :rvm_path, '/home/raymond/.rvm/bin/rvm'
  set :rails_env, 'development'
  set :unicorn_env, 'development'
end

task :production do
  set :domain, production_ip
  set :user, user_name
  set :port, port
  set :rvm_path, '/usr/local/rvm/bin/rvm'
  set :rails_env, 'production'
  set :unicorn_env, 'production'
end

desc "Deploys the current version to the server."
task :deploy => :environment do
  to :before_hook do
    # Put things to run locally before ssh
  end
  deploy do
    # sidekiq stop accepting new workers
    invoke :'sidekiq:quiet'

    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'
    invoke :'bundle:install'
    invoke :'rails:db_migrate'
    invoke :'rails:assets_precompile'
    invoke :'deploy:cleanup'

    to :launch do
      invoke :'sidekiq:restart'
      invoke :'unicorn:restart'
    end
  end
end

# 新增加的 unicorn重启相关命令
namespace :unicorn do
  set :unicorn_pid, "#{deploy_to}/tmp/pids/unicorn.pid"

  desc "Start Unicorn"
  task :start => :environment do
    queue 'echo "-----> Start Unicorn"'
    queue! %{
      cd #{deploy_to}/#{current_path} && bundle exec unicorn_rails -c config/unicorn.rb -E production -D
    }
  end

  desc "Stop Unicorn"
  task :stop do
    queue 'echo "-----> Stop Unicorn"'
    queue! %{
      kill -QUIT `cat "#{unicorn_pid}"` && rm -rf "#{unicorn_pid}" && echo "Stop Ok" && exit 0
      echo >&2 "Not running"
    }
  end

  desc "Restart unicorn"
  task :restart => :environment do
    invoke 'unicorn:stop'
    invoke 'unicorn:start'
  end
end

总结

目前,使用以上配置,使用 mina 远程部署,之前部署中所遇到的 unicorn 重启后,业务不生效的问题,得到了解决。

希望该帖子能够帮助到,之前遇到相同问题,但还没有解决的用户。

如果之前使用 mina 部署的用户,没有遇到和我类似的问题,个人建议大家继续使用 mina-unicorn 这个 gem,毕竟使用起来也很方便。

本身的重启是使用 unicorn 的 USR2 信号进行无缝重启的,唯一的问题是等待时间。要排查这个问题,你需要了解 unicorn 无缝重启的过程。

Reply to Xenofex

是的,mina-unicorn 的 restart_unicorn 里面有一行就是设置的等待时间

def restart_unicorn
  %{
    #{duplicate_unicorn}
    sleep #{fetch(:unicorn_restart_sleep_time)}; # in order to wait for the (old) pidfile to show up
    if #{old_unicorn_is_running?}; then
        #{unicorn_send_signal("QUIT", get_old_unicorn_pid)};
    fi
  }
end
You need to Sign in before reply, if you don't have an account, please Sign up first.