notebook

都内でWEB系エンジニアやってます。

Capistrano3+Angularのデプロイコマンドがいつまで経っても終わらない時の対処法

Rails5 + Angular6で開発していてwebpackerを使わずにCapistranoを使ってAngularのビルドコマンドを直に実行していました

.....が、待てどくらせどAngularのビルドが終わらない!

大体10分くらい待たされているよう

これではデプロイどころではないので調べました

前提

プロジェクトの構成としてRailsのルートディレクトリにfrontendディレクトリがあってそこにAngularのファイル郡があります

デプロイはCapistranoを使っているのでfrontendへ移動してビルドコマンドを叩くという感じです

コマンドのー部を抜粋します

  • lib/capistrano/tasks/angular.rake
namespace :angular do
  task :modules_install do
    run_locally do
      execute("cd frontend && npm install")
    end
  end

  task :build do
    run_locally do
      execute("cd frontend && npx ng build --prod --aot")
    end
  end

  task :s3put do
    run_locally do
      execute("aws s3 cp frontend/dist/project s3://prject-root --recursive")
    end
  end
end
  • modules_install
  • build
  • s3put

の順で実行されていきます

切り分けを行うために1つづつコマンドを実行していくとボトルネックはbuildであるという事がわかりました

そしてプロセスを見るとビルドのコマンド自体は終わっているのに次のtaskへ進まない。。。

buildの中で何をしているのかpryを入れて見てみたところ

怪しそうな箇所を見つけました

/home/vagrant/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/sshkit-1.16.1/lib/sshkit/backends/local.rb def execute_command(cmd)

    41: def execute_command(cmd)
 => 42:   output.log_command_start(cmd)
    43:
    44:   cmd.started = Time.now
    45:
    46:   Open3.popen3(cmd.to_command) do |stdin, stdout, stderr, wait_thr|
    47:     stdout_thread = Thread.new do
    48:       while (line = stdout.gets) do
    49:         cmd.on_stdout(stdin, line)
    50:         output.log_command_data(cmd, :stdout, line)
    51:       end
    52:     end
    53:
    54:     stderr_thread = Thread.new do
    55:       while (line = stderr.gets) do
    56:         cmd.on_stderr(stdin, line)
    57:         output.log_command_data(cmd, :stderr, line)
    58:       end
    59:     end
    60:
    61:     stdout_thread.join
    62:     stderr_thread.join
    63:
    64:     cmd.exit_status = wait_thr.value.to_i
    65:
    66:     output.log_command_exit(cmd)
    67:   end
    68: end

..... ..... .....

From: /home/vagrant/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/airbrussh-1.3.0/lib/airbrussh/delegating_formatter.rb @ line 24:
Owner: Airbrussh::DelegatingFormatter
Visibility: public
Number of lines: 3

define_method(method) do |*args|
  formatters.map { |f| f.public_send(method, *args) }.last
end

[6] pry(#<SSHKit::Formatter::Airbrussh>)> method
=> "log_command_start"

..... ..... .....

From: /home/vagrant/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/sshkit-1.16.1/lib/sshkit/formatters/pretty.rb @ line 19 SSHKit::Formatter::Pretty#log_command_start:

    18: def log_command_start(command)
 => 19:   host_prefix = command.host.user ? "as #{colorize(command.host.user, :blue)}@" : 'on '
    20:   message = "Running #{colorize(command, :yellow, :bold)} #{host_prefix}#{colorize(command.host, :blue)}"
    21:   write_message(command.verbosity, message, command.uuid)
    22:   write_message(Logger::DEBUG, "Command: #{colorize(command.to_command, :blue)}", command.uuid)
    23: end

ここまで追ったのですが見失ってしまいました

From: /home/vagrant/.anyenv/envs/rbenv/versions/2.5.1/lib/ruby/2.5.0/forwardable.rb @ line 223 SSHKit::Formatter::Abstract#colorize:

    220: def #{ali}(*args, &block)
    221:   #{pre}
    222:   begin
 => 223:     #{accessor}
    224:   end#{method_call}#{FILTER_EXCEPTION}

ココらへんでどういう動きをしているのかがわからなくなってしまいました

cmd
=> #<SSHKit::Command:0x00007f7f3150b498
 @args=[],
 @command="cd frontend && npx ng build --prod --aot",
 @full_stderr="",
 @full_stdout="",
 @options=
  {:raise_on_non_zero_exit=>true,
   :run_in_background=>false,
   :in=>nil,
   :env=>nil,
   :host=>#<SSHKit::Host:0x00007f7f2e166368 @hostname="localhost", @keys=[], @local=true, @user="vagrant">,
   :user=>nil,
   :group=>nil},
 @stderr="",
 @stdout="">
output
SSHKit::Formatter::Airbrussh
.....
.....
.....

正直途中で見失ったのですがどうもoutputが実行しているlog_command_strtコマンドが怪しいというところまでは追えました

なのでoutputに何が使われているのか見てみたところAirbrusshというのが出てきたので何か見てみるとログのフォーマッタツールのようです

フォーマッタだし関係ないかーなんて思っていたのであまり疑ってなかったのですが試しにフォーマッタをprettyに変えたところとくに待たされることがなくなりました

とういことで詳細まで終えていないもののAirbrusshで`Angularのビルド時の出力をフォーマットする処理がうまく行ってない様です

angular/cliでbuild以外のコマンドを実行したときは問題ないことを確認したので

build時の挙動にも相性的な問題がありそう

デフォルトだとangular-cliでbuildすると進捗表示が出てくるのでそれをなくしてみます

--no-progressオプションをつけてビルドすると待たされることがなくなった

f:id:swfz:20181230043615g:plain

この進捗表示が良くないらしい

なのでワークアラウンドではあるのですが解決策として2つ挙げられることがわかりました

  • capistranoのフォーマッタ設定を変える
set :format, :pretty
  • Angularのビルド時に進捗表示を出さない
--no-progress

これでデプロイ時のAngularのビルドに待たされることがなくなりました

これ以外にもcapistrano側のオプションをいじることで効果出そうな気がするが試す気力がなくなってしまったためこれで終了

とりあえず快適!