2018-03-23

pumaの再起動時のディレクトリについて

capistranoでデプロイをしてもRailsアプリのコードが反映されない!とハマったので備忘録

状況は以下の通り

supervisordのサービスの設定ファイルは以下の通り

[program:my_app]
command=bundle exec puma -C config/puma.rb
directory=/root/current
process_name=%(program_name)s
stdout_logfile=/var/log/supervisor/supervisord.log
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=5
stdout_capture_maxbytes=1MB
redirect_stderr=true

pumaの設定はファイルはこんな感じ。

threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }

原因

supervisordのdirectoryでsymlinkを指定すると、起動するプロセスのディレクトリはsymlinkを展開した実際のディレクトリにcdします。つまり、/root/currentを指定すると/root/app1のディレクトリにcdすることになります。

コードで追うと以下の部分。supervisordのバージョンは3.3.4です。

class Subprocess(object):
    def _spawn_as_child(self, filename, argv):
        options = self.config.options
# ...
            try:
                cwd = self.config.directory
                if cwd is not None:
                    options.chdir(cwd)
            except OSError, why:
# ...
            # set umask, then execve
            try:
                if self.config.umask is not None:
                    options.setumask(self.config.umask)
                options.execve(filename, argv, env)
            except OSError, why:

指定したdirectoryの値でcdしてからexecveしています。

一方、pumaの起動ディレクトリは設定ファイルで指定されていない場合、カレントディレクトリになります。

module Puma
  class Launcher
    def initialize(conf, launcher_args={})
# ...
      generate_restart_data

# ...
      Dir.chdir(@restart_dir)

# ...
    def generate_restart_data
      if dir = @options[:directory]
        @restart_dir = dir

# ...
      end

      @restart_dir ||= Dir.pwd

capistranoはsymlinkでリリースを切り替えますが、@restart_dirは古いディレクトリの状態で切り替わらず変更が反映されないことになります。

解決策としては、設定ファイルのdirectoryにsymlinkのパスを設定するだけでOKです。これによって、pumaが起動されるときにdirectoryのsymlinkを解決することになります。再起動時も必ずsymlinkを経由してcdするため、新しくなったcurrentのリンク先を参照することになります。

directory '/root/current'
このエントリーをはてなブックマークに追加