Capistrano3で並列制御を行う

Capistranoでは、デフォルトではすべてタスクが並列で実行されるようになっていますが、次の設定で並列実行できるサーバの数を制御できます。

設定方法

  • タスク個別に設定する場合
task :uptime do
  on roles(:all), { in: :groups, limit: 5, wait: 2 } do
    execute :uptime
  end
end

この場合は、5台ずつ実行し、間2秒待機ということになります。 例えば、全部10サーバ実行するとしたら、10サーバのうち5台タスクが実行される => 2秒待ち => 残り5台タスクが実行される という流れになります。

  • デフォルトを変更する場合
SSHKit.config.default_runner_config = { in: :groups, limit: 5, wait: 2 }

設定の内容は上記と同じです。 個別にタスクが設定されている場合は、そちらが優先されます。

デプロイタスクで使えるか?

以前、10台を超えるようなアプリケーションサーバへデプロイした際に、クライアントのオープンできるファイルディスクリプタの上限を超えてしまいデプロイができないという問題がありました。 その際は、ファイルディスクリプタの上限値を上げて対応しましたが、根本的な対応として並列で実行できるサーバの数を調整して対応できないかを調べてみました。

結果的には、deploy:publishing のタスク(currentディレクトリの切り替え) https://github.com/capistrano/capistrano/blob/96fdb4c8c54772fa6d5a4ed29cc6df8a2f65ee7b/lib/capistrano/tasks/deploy.rake#L99-L107 にかかる時間差がgroupごとに発生してしまうため、このままだと、これが許容できる場合はOK。できない場合はNGとなります。

ほとんどのケースでは、アプリケーションを同時に反映して欲しいのでほぼNGでしょう。

対策として、

Rake::Task["deploy:symlink:release"].clear
namespace :deploy do
  namespace :symlink do
    desc "Symlink release to current"
    task :release do
      on release_roles(:all), in: :parallel do
        tmp_current_path = release_path.parent.join(current_path.basename)
        execute :ln, "-s", release_path, tmp_current_path
        execute :mv, tmp_current_path, current_path.parent
      end
    end
  end
end

こういう感じで、上書きしてあげればよさそうですが、ちょっと無理矢理感が強いので避けたい気持ち・・・ アップデートで内容が変わる可能性もありますし。 何か解決できる案があれば教えてください。

参考: https://github.com/capistrano/sshkit#parallel http://asobo.hatenablog.jp/entry/2016/01/17/115631 http://blog.livedoor.jp/sonots/archives/39007111.html