Przyspieszenie zasobów: precompile z rails 3.1/3.2 Capistrano deployment
Moje wdrożenia są powolne, trwają co najmniej 3 minuty. Zadaniem slow Capistrano podczas wdrażania jest assets:precompile. Zajmuje to prawdopodobnie 99% całkowitego czasu wdrożenia. Jak mogę to przyspieszyć? Czy powinienem wstępnie skompilować Moje zasoby na moim lokalnym komputerze i dodać je do mojego Git repo?
Edit: dodanie config.assets.initialize_on_precompile = false
do mojej aplikacji.plik RB zmniejszył czas prekompilacji z pół minuty, ale nadal jest powolny.
7 answers
Chodzi o to, że jeśli nie zmienisz swoich zasobów, nie musisz ich przekompilować za każdym razem:
To jest rozwiązanie, które Ben Curtis proponuje dla wdrożenia z git:
namespace :deploy do
namespace :assets do
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if releases.length <= 1 || capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | wc -l").to_i > 0
run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
else
logger.info "Skipping asset pre-compilation because there were no asset changes"
end
end
end
end
Oto inne podejście oparte na wieku aktywów (https://gist.github.com/2784462) :
set :max_asset_age, 2 ## Set asset age in minutes to test modified date against.
after "deploy:finalize_update", "deploy:assets:determine_modified_assets", "deploy:assets:conditionally_precompile"
namespace :deploy do
namespace :assets do
desc "Figure out modified assets."
task :determine_modified_assets, :roles => assets_role, :except => { :no_release => true } do
set :updated_assets, capture("find #{latest_release}/app/assets -type d -name .git -prune -o -mmin -#{max_asset_age} -type f -print", :except => { :no_release => true }).split
end
desc "Remove callback for asset precompiling unless assets were updated in most recent git commit."
task :conditionally_precompile, :roles => assets_role, :except => { :no_release => true } do
if(updated_assets.empty?)
callback = callbacks[:after].find{|c| c.source == "deploy:assets:precompile" }
callbacks[:after].delete(callback)
logger.info("Skipping asset precompiling, no updated assets.")
else
logger.info("#{updated_assets.length} updated assets. Will precompile.")
end
end
end
end
Jeśli wolisz prekompilować swoje zasoby lokalnie, możesz użyć tego zadania:
namespace :deploy do
namespace :assets do
desc 'Run the precompile task locally and rsync with shared'
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if releases.length <= 1 || capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | wc -l").to_i > 0
%x{bundle exec rake assets:precompile}
%x{rsync --recursive --times --rsh=ssh --compress --human-readable --progress public/assets #{user}@#{host}:#{shared_path}}
%x{bundle exec rake assets:clean}
else
logger.info 'Skipping asset pre-compilation because there were no asset changes'
end
end
end
end
Innym ciekawym podejściem może być użycie Git hook.
Na przykład możesz dodać ten kod do .git/hooks/pre-commit
, który sprawdza, czy są jakieś różnice w plikach zasobów, a następnie wstępnie je kompiluje i dodaje do bieżącego commita.
#!/bin/bash
# source rvm and .rvmrc if present
[ -s "$HOME/.rvm/scripts/rvm" ] && . "$HOME/.rvm/scripts/rvm"
[ -s "$PWD/.rvmrc" ] && . "$PWD/.rvmrc"
# precompile assets if any have been updated
if git diff-index --name-only HEAD | egrep '^app/assets' >/dev/null ; then
echo 'Precompiling assets...'
rake assets:precompile:all RAILS_ENV=production RAILS_GROUPS=assets
git add public/assets/*
fi
Jeśli zdecydujesz się na takie podejście, prawdopodobnie będziesz musiał zmienić swoje config/environments/development.rb
dodając:
config.assets.prefix = '/assets_dev'
Tak, że podczas rozwoju nie będziesz służył wstępnie skompilowanych aktywów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-02 14:00:25
Właśnie napisałem klejnot do rozwiązania tego problemu wewnątrz szyn, o nazwie turbo-sprockets-rails3 . Przyspiesza assets:precompile
tylko rekompilując zmienione pliki i kompilując tylko raz w celu wygenerowania wszystkich zasobów. To działa po wyjęciu z pudełka dla Capistrano, ponieważ twój katalog zasobów jest współdzielony między wydaniami.
Jest to o wiele bardziej kuloodporne niż rozwiązania, które używają git log
, ponieważ moja łatka analizuje źródła Twoich aktywów, nawet jeśli pochodzą z klejnotu. Na przykład, jeśli zaktualizujesz jquery-rails
, zostanie wykryta zmiana dla application.js
, a tylko application.js
zostanie skompilowana.
Zauważ, że próbuję również połączyć tę łatkę z Rails 4.0.0 i ewentualnie Rails 3.2.9 (zobacz https://github.com/rails/sprockets-rails/pull/21 ). ale na razie byłoby super, gdybyś mógł mi pomóc przetestowaćturbo-sprockets-rails3 gem, i daj mi znać, jeśli masz jakieś problemy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 00:11:28
Rozwiązanie Tommasopa nie działa, gdy włączona jest kopia w pamięci podręcznej, moja zmodyfikowana wersja:
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if capture("cd #{shared_path}/cached-copy && git diff #{from}.. --stat | grep 'app/assets' | wc -l").to_i > 0
run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{Rubber.env} #{asset_env} assets:precompile:primary}
else
logger.info "Skipping asset pre-compilation because there were no asset changes"
end
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-28 09:33:02
Możesz zapisać wysiłek serwera dotyczący wstępnej kompilacji zasobów, wykonując to samo (wstępnie kompilowanie zasobów) w systemie lokalnym. I przechodzę na serwer.
from = source.next_revision(current_revision) rescue nil
if from.nil? || capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | wc -l").to_i > 0
ln_assets
run_locally "rake assets:precompile"
run_locally "cd public; tar -zcvf assets.tar.gz assets"
top.upload "public/assets.tar.gz", "#{shared_path}", :via => :scp
run "cd #{shared_path}; tar -zxvf assets.tar.gz"
run_locally "rm public/assets.tar.gz"
else
run "ln -s #{shared_path}/assets #{latest_release}/public/assets"
logger.info "Skipping asset pre-compilation because there were no asset changes"
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-11 12:25:38
Rozwiązanie zaproponowane przez Bena Curtisa nie działa dla mnie, ponieważ nie kopiuję .folder git podczas instalacji (wolny i bezużyteczny):
set :scm, :git
set :deploy_via, :remote_cache
set :copy_exclude, ['.git']
Używam poniższego fragmentu, whitout load 'deploy/assets'
task :assets, :roles => :app do
run <<-EOF
cd #{release_path} &&
rm -rf public/assets &&
mkdir -p #{shared_path}/assets &&
ln -s #{shared_path}/assets public/assets &&
export FROM=`[ -f #{current_path}/REVISION ] && (cat #{current_path}/REVISION | perl -pe 's/$/../')` &&
export TO=`cat #{release_path}/REVISION` &&
echo ${FROM}${TO} &&
cd #{shared_path}/cached-copy &&
git log ${FROM}${TO} -- app/assets vendor/assets | wc -l | egrep '^0$' ||
(
echo "Recompiling assets" &&
cd #{release_path} &&
source .rvmrc &&
RAILS_ENV=production bundle exec rake assets:precompile --trace
)
EOF
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-18 19:18:13
Są chwile, kiedy muszę wymusić prekompilację skip asset podczas wdrażania poprawki jak najszybciej. Używam następujący hack jako uzupełnienie innych odpowiedzi do pracy.
callback = callbacks[:after].find{|c| c.source == "deploy:assets:precompile" }
callbacks[:after].delete(callback)
after 'deploy:update_code', 'deploy:assets:precompile' unless fetch(:skip_assets, false)
Ten skrypt zmieni wbudowany atut-precompile hooking, więc zostanie wywołany na podstawie parametru skip_assets . Mogę zadzwonić cap deploy -S skip_assets=true
, aby całkowicie pominąć prekompilację aktywów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-15 03:57:17
OP wyraźnie poprosił o Capistrano, ale jeśli instalujesz bez dedykowanego narzędzia wdrażania (poprzez skrypt bash, Ansible playbook lub podobne), możesz użyć następujących kroków, aby przyspieszyć wdrażanie Rails:]}
Pomiń instalację pakietu
bundle check
zwraca1
jeśli istnieją klejnoty do zainstalowania (1
w przeciwnym razie), więc łatwo jest pominąć instalację pakietu, jeśli nie jest to konieczne.Skip asset precompilation
Usegit rev-parse HEAD
przed pobraniem zmian i zapisaniem aktualnej wersji SHA w zmiennej (powiedzmy$previous_commit
). Następnie wyciągnij zmiany i sprawdź, czy zasoby uległy zmianie za pomocą poleceniagit diff --name-only $previous_commit HEAD | grep -E "(app|lib|vendor)/assets"
. Jeśli to zwróci$1
, możesz bezpiecznie pominąć prekompilację zasobów(jeśli używasz wdrożeń opartych na wydaniu, możesz chcieć skopiować zasoby do katalogu nowego wydania).Pomiń migracje baz danych
Jeśli używasz MySQL, użyj poleceniamysql --user=USER --password=PASSWORD --batch --skip-column-names --execute="USE MYAPP; SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;"
z katalogu głównego aplikacji, aby uzyskać nazwę najnowsza migracja stosowana. Porównaj to z wyjściem polecenials db/migrate | tail -1 | cut -d '_' -f 1
(które zwraca najnowszą dostępną migrację). Jeśli różnią się, musisz przeprowadzić migrację. Jeśli nie, można pominąć migracje baz danych.
Programiści rails wdrażający z Ansible mogą jeszcze bardziej skrócić czas wdrażania, wyłączając gromadzenie faktów, jeśli nie jest to konieczne (gather_facts: no
) i używając SSH pipelining (export ANSIBLE_SSH_PIPELINING=1
).
Jeśli chcesz więcej szczegółów, napisałem niedawno artykuł na ten temat.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-11 23:46:35