Je travaille sur un projet Rails 3.2 et les actifs ont augmenté un peu ces derniers mois, bien que je ne considère pas le projet comme important. Les actifs sont constitués de JS (pas de café- script), et les fichiers SASS; nous avons pas mal d'images mais elles y sont moins depuis les premiers jours donc je ne pense pas qu'elles soient un facteur substantiel. Nous pouvons avoir une douzaine de libs et la plupart sont petites, le plus grand est Jquery UI JS. Le déploiement se fait via Capistrano et il est devenu évident que le déploiement vers la mise en scène était beaucoup plus rapide que vers la production. mon ordinateur portable comme suit:
$ time Rails_ENV=production bundle exec rake assets:precompile
^Crake aborted!
[Note I aborted this run as I felt it was getting stupidly long...]
real 52m33.656s
user 50m48.993s
sys 1m42.165s
$ time Rails_ENV=staging bundle exec rake assets:precompile
real 0m41.685s
user 0m38.808s
sys 0m2.803s
$ time Rails_ENV=development bundle exec rake assets:precompile
real 0m12.157s
user 0m10.567s
sys 0m1.531s
Alors je me suis gratté la tête. Pourquoi existe-t-il des différences aussi importantes entre les différents environnements? Je peux comprendre l'écart entre le développement et la mise en scène, mais nos configurations pour la mise en scène et la production sont identiques. (Je dois souligner que la compilation de la production se terminera après environ 2 heures!)
Alors que le résultat final accélère ma précompilation, je veux y parvenir en comprenant où va tout le temps et pourquoi il y a de si grandes différences entre les environnements Rails. J'ai vu d'autres articles sur l'utilisation de différents compresseurs et autres, mais je ne trouve aucune information sur la façon de déboguer ces tâches de râteau pour déterminer où le temps est passé et identifier les paramètres qui peuvent causer de telles différences dramatiques.
Je ne sais pas quelles informations supplémentaires les gens peuvent avoir besoin, donc ils mettront à jour si et quand les commentaires le demandent. TIA
Mise à jour: informations supplémentaires fournies ci-dessous
config/environments/production.rb
et config/environments/staging.rb
(ils sont exactement les mêmes):
MyRailsApp::Application.configure do
# Code is not reloaded between requests
config.cache_classes = true
# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = true
config.static_cache_control = "public, max-age=31536000"
config.action_controller.asset_Host = "//#{MyRailsApp::CONFIG[:cdn]}"
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
# Generate digests for assets URLs
config.assets.digest = true
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
end
La base config/application.rb est:
require File.expand_path('../boot', __FILE__)
require 'Rails/all'
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module MyRailsApp
CONFIG = YAML.load_file(File.join(File.dirname(__FILE__), 'config.yml'))[Rails.env]
class Application < Rails::Application
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += %W(#{config.root}/app/workers)
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
# Enable the asset pipeline
config.assets.enabled = true
# Stop precompile from looking for the database
config.assets.initialize_on_precompile = false
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
# Fix fonts in assets pipeline
# http://stackoverflow.com/questions/6510006/add-a-new-asset-path-in-Rails-3-1
config.assets.paths << Rails.root.join('app','assets','fonts')
config.middleware.insert 0, 'Rack::Cache', {
:verbose => true,
:metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"),
:entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
} # unless Rails.env.production? ## uncomment this 'unless' in Rails 3.1,
## because it already inserts Rack::Cache in production
config.middleware.insert_after 'Rack::Cache', 'Dragonfly::Middleware', :images
config.action_mailer.default_url_options = { :Host => CONFIG[:email][:Host] }
config.action_mailer.asset_Host = 'http://' + CONFIG[:email][:Host]
end
end
Fichier Gem:
source 'http://rubygems.org'
gem 'Rails', '3.2.13'
gem 'mysql2'
gem 'dragonfly', '>= 0.9.14'
gem 'rack-cache', :require => 'rack/cache'
gem 'will_paginate'
gem 'dynamic_form'
gem 'Amazon_product' # for looking up Amazon ASIN codes of books
gem 'geoip'
gem 'mobile-fu'
gem 'airbrake'
gem 'newrelic_rpm'
gem 'bartt-ssl_requirement', '~>1.4.0', :require => 'ssl_requirement'
gem 'dalli' # memcache for api_cache
gem 'api_cache'
gem 'daemons'
gem 'delayed_job_active_record'
gem 'attr_encrypted'
gem 'rest-client'
gem 'json', '>= 1.7.7'
gem 'carrierwave' # simplify file uploads
gem 'net-scp'
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'therubyracer'
gem 'sass-Rails', '~> 3.2.3'
gem 'compass', '~> 0.12.alpha'
gem 'uglifier', '>= 1.0.3'
gem 'jquery-fileupload-Rails'
end
gem 'jquery-Rails'
gem 'api_bee', :git => 'git://github.com/ismasan/ApiBee.git', :ref => '3cff959fea5963cf46b3d5730d68927cebcc59a8'
gem 'httparty', '>= 0.10.2'
gem 'Twitter'
# Auth providers
gem 'omniauth-facebook'
gem 'omniauth-Twitter'
gem 'omniauth-google-oauth2'
gem 'omniauth-identity'
gem 'omniauth-readmill'
gem 'bcrypt-Ruby', "~> 3.0.0" # required for omniauth-identity
gem 'mail_view'
# To use ActiveModel has_secure_password
# gem 'bcrypt-Ruby', '~> 3.0.0'
# Deploy with Capistrano
group :development do
gem 'capistrano'
gem 'capistrano-ext'
gem 'capistrano_colors'
gem 'rvm-capistrano'
# requirement for Hoof, Linux equivalent of Pow
gem 'Unicorn'
end
group :test, :development do
gem 'rspec-Rails'
gem 'pry'
gem 'pry-Rails'
end
group :test do
gem 'factory_girl_Rails'
gem 'capybara'
gem 'cucumber-Rails'
gem 'database_cleaner'
gem 'launchy'
gem 'Ruby-debug19'
# Pretty printed test output
gem 'shoulda-matchers'
gem 'simplecov', :require => false
gem 'email_spec'
gem 'show_me_the_cookies'
gem 'vcr'
gem 'webmock', '1.6'
end
Cela ne répond pas entièrement à votre question, mais je pense que c'est un début assez décent. Comme vous le verrez, la réponse précise dépendra de l'application individuelle, des versions de gemmes, etc.
Donc. Pour le travail lié aux actifs, comme vous le savez, Rails utilise une bibliothèque appelée Sprockets, qui dans les versions plus récentes de Rails est, je crois, connectée à Rails en tant que Railtie. Il initialise un "environnement" Sprockets qui peut faire des choses comme regarder votre manifeste d'actifs, charger ces fichiers, les compresser, donner aux actifs compilés des noms sensés, etc.
Par défaut, ce Sprockets::Environment
Enregistre son activité dans STDERR
avec un niveau de journal de FATAL
, ce qui n'est pas très utile dans ces situations. Heureusement, le Sprockets::Environment
(À partir de 2.2.2
) Possède un attribut de logger inscriptible que vous pouvez patcher via Rails, en utilisant un initialiseur.
Alors, voici ce que je suggère, pour commencer:
Dans config/initializers
, Créez un fichier, quelque chose comme asset_logging.rb
. Dans ce document, mettez:
Rails.application.config.assets.logger = Logger.new($stdout)
Cela écrase l'enregistreur par défaut avec un qui enverra plus d'informations à STDOUT
. Une fois que vous avez configuré cela, exécutez votre tâche de pré-compilation des ressources:
rake Rails_ENV=production assets:precompile
Et vous devriez voir légèrement une sortie plus intéressante, comme:
...
Compiled jquery.ui.core.js (0ms) (pid 66524)
Compiled jquery.ui.widget.js (0ms) (pid 66524)
Compiled jquery.ui.accordion.js (10ms) (pid 66524)
...
Mais, au final, la réponse finale dépendra:
Comme vous l'avez déjà appris, la journalisation de la spéléologie au niveau de la tâche Rake, ou même au niveau Rails, ne donne pas beaucoup d'informations. Et même rendre Sprockets lui-même verbeux (voir ci-dessus) ne vous en dit pas trop.
Si vous vouliez aller plus loin que Sprockets, vous pouvez probablement corriger les différents moteurs et processeurs que Sprockets enchaîne consciencieusement pour faire fonctionner le pipeline d'actifs. Par exemple, vous pouvez examiner les capacités de journalisation de ces composants:
Sass::Engine
(Convertit SASS en CSS)Uglifier
(wrapper de compresseur JavaScript)ExecJS
(exécute JavaScript dans Ruby; une dépendance à la fois de Sprockets et d'Uglifier)therubyracer
(V8 intégré dans Ruby; utilisé par ExecJS
)Mais je laisserai tout cela comme "un exercice pour le lecteur". S'il y a une solution miracle, j'aimerais certainement le savoir!
il y a un tas de causes possibles à ce problème.
pour une cause possible, j'aimerais savoir comment le temps de compilation des actifs a augmenté dans les différents environnements pour vos derniers déploiements. cela peut indiquer si le problème concerne uniquement les environnements ou la compilation d'actifs elle-même. vous pourriez utiliser git bisect
pour ça. j'ai généralement mes applications déployées pour la mise en scène via un jenkins ou un autre système ci afin que je puisse voir toutes les variations de temps de déploiement et quand elles ont été introduites.
cela peut se résumer à une utilisation intensive des ressources CPU, MEMORY (tout échange?), IO. si vous compilez les actifs sur les systèmes de production, ils pourraient être occupés à répondre à votre demande d'applications. allez sur votre système, faites un top
pour les ressources, peut-être qu'il y a trop de descripteurs de fichiers en même temps (lsof
est bon pour ça).
une autre chose peut être que vous chargez ou mettez en cache certaines données pour votre application. les bases de données sont généralement beaucoup plus volumineuses dans les environnements de production et de transfert que dans les boîtes de développement. vous pouvez simplement mettre un peu de Rails.logger
appelle dans vos initialiseurs ou whaterver.
Je pense que vous devez voir les paramètres d'utilisation du processeur sur votre serveur Prod.
De plus, il est possible que les actifs soient précompilés plusieurs fois. Je suggérerais de créer un répertoire d'actifs dans un répertoire partagé créé par capistrano, en copiant vos modifications dans le même et en le liant à vos applications lors du déploiement.
Voici comment je le fais,
after "deploy:update_code" do
run "export Rails_ENV=production"
run "ln -nfs #{shared_path}/public/assets #{release_path}/public/assets"
# Also for logs and temp section.
# run "ln -nfs #{shared_path}/log #{release_path}/log"
# run "ln -nfs #{shared_path}/tmp #{release_path}/tmp"
#Sudo "chmod -R 0777 #{release_path}/tmp/"
#Sudo "chmod -R 0777 #{release_path}/log/"
end