LoginSignup
8

More than 5 years have passed since last update.

capistrano-rails + asset_sync + S3で構成されたasset配信の仕組みを解明する

Posted at

asset_syncを使って、RailsのassetsをS3から配信するパターンはほぼ定石となっている感があり、現在携わっているサービスも例外に漏れずこのパターンを採用しています。

そのasset_syncですが、導入がカンタンであまり迷うことがないので、勢いブラックボックスになりがちなのかなと思ってます。(少なくとも自分は詳しく知りませんでした^^;)

今回、assetsの配信周りで発生したトラブルを契機に、capistrano-railsとasset_syncについて調べたので、備忘録としてまとめておきます。

なお、運用環境は以下の通りです。

  • sprockets (3.6.3)
  • capistrano (3.4.1)
  • capistrano-rails (1.1.7)
  • asset_sync (1.0.0)
  • fog (1.38.0)

capistrano-rails

Capistrano v3向けのRails固有タスクを追加するためのgemです。

Capfileに

require 'capistrano/rails/assets'

と書くだけで、updated hook に deploy:compile_assets 等のタスクが登録されます。

  after 'deploy:updated', 'deploy:compile_assets'
  after 'deploy:updated', 'deploy:cleanup_assets'
  after 'deploy:updated', 'deploy:normalize_assets'
  after 'deploy:reverted', 'deploy:rollback_assets'

https://github.com/capistrano/rails/blob/v1.2.3/lib/capistrano/tasks/assets.rake#L59-L62

では、deploy:compile_assetsが何をしているかというと、以下を見るとわかります。

  namespace :assets do
    task :precompile do
      on release_roles(fetch(:assets_roles)) do
        within release_path do
          with rails_env: fetch(:rails_env) do
            execute :rake, "assets:precompile"
          end
        end
      end
    end
  end

rake assets:precompile

rake assets:precompileで実行しているタスクの詳細を知りたい場合は、

bundle exec rake assets:precompile --trace

を実行すればokです。

$ bundle exec rake assets:precompile --trace
** Invoke assets:precompile (first_time)
** Invoke assets:environment (first_time)
** Execute assets:environment
** Invoke environment (first_time)
** Execute environment
** Execute assets:precompile
** Invoke assets:sync (first_time)
** Invoke assets:environment
** Execute assets:sync

assets:precompile後にassets:syncを実行していることがわかります。

どういった仕組みで実行しているかは、asset_syncのREADMEに書かれています。以下に、一部抜粋します。

  if Rake::Task.task_defined?("assets:precompile:nondigest")
    Rake::Task["assets:precompile:nondigest"].enhance do
      Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile
    end
  else
    Rake::Task["assets:precompile"].enhance do
      Rake::Task["assets:sync"].invoke if defined?(AssetSync) && AssetSync.config.run_on_precompile
    end
  end

Rake::Task#enhance により、assets:precompile => assets:sync という順序でタスクが実行されるようになっています。

asset_sync

assets:syncタスクはシンプルでAssetSync.syncを実行するだけです。

  namespace :assets do
    desc "Synchronize assets to S3"
    task :sync => :environment do
      AssetSync.sync
    end
  end

コードを追うと、AssetSync::Storage#syncに辿り着きます。これがS3への同期処理のコア部分です。

    def sync
      # fixes: https://github.com/rumblelabs/asset_sync/issues/19
      log "AssetSync: Syncing."
      upload_files
      delete_extra_remote_files unless keep_existing_remote_files?
      log "AssetSync: Done."
    end

さらに、upload_files と delete_extra_remote_files の実装を見てみます。

    def upload_files
      # get a fresh list of remote files
      remote_files = ignore_existing_remote_files? ? [] : get_remote_files
      # fixes: https://github.com/rumblelabs/asset_sync/issues/19
      local_files_to_upload = local_files - ignored_files - remote_files + always_upload_files
      local_files_to_upload = (local_files_to_upload + get_non_fingerprinted(local_files_to_upload)).uniq
      ...

upload_filesメソッドではlocal_files と remote_files の差分をチェックして、remoteに存在しないファイルをアップロードしていることが見てとれます。

    def delete_extra_remote_files
      log "Fetching files to flag for delete"
      remote_files = get_remote_files
      # fixes: https://github.com/rumblelabs/asset_sync/issues/19
      from_remote_files_to_delete = remote_files - local_files - ignored_files - always_upload_files

delete_extra_remote_filesでも差分をチェックしていますが、こちらはlocalに存在しないファイルを削除していることがわかります。

なお、delete_extra_remote_filesを実行するかは設定(config.existing_remote_files)により、決めることができます。

# AssetSync::Config
    def existing_remote_files?
      ['keep', 'ignore'].include?(self.existing_remote_files)
    end

まとめ

だいぶ長くなったのでまとめます。

  • capistrano-railsはdeploy:compile_assets等のcapタスクを追加するgem
  • asset_syncはrake assets:precompileからinvokeされる
  • asset_syncはlocalとremoteのファイル差分を計算し、よしなに同期してくれる

References

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8