There's a number of problems, but foremost is that there's no good way to "roll back" assets, and there's no concept of keeping assets that might be used by old versions of pages cached in CDNs, when they have been replaced by newer assets. This is a problem of the manifest system, and of the `assets` directory always representing the current newest state, not the collective state since the beginning of time. Maintaining state from the beginning of time would bring it's own problems, thus many of the workarounds about tracking old, and new assets are time consuming and sub optimal, and unfortunatley people need them. There's a cap task which touches `mtimes` of all referenced assets, which can typically take 5 minutes to complete. It's naïve, and stupid, but it's the only solution (that we could come up with) to a real asset pipeline problem.
I'm also of the opinion that compiling assets in production as a part of your deployment process is insane, there's so much magic in the Rails asset pipeline that it's not uncommon to turn up bugs where tables don't exist, and the rails app can't initialize, or some javascript runtime environment isn't found which can leave your deployment in a broken state.
I'm firmly of the opinion that assets should be compiled and checked in, but then of course you run into problems with rails serving those in development mode, rather than the development files.
All these issues are fixable, but they're all indicative of tools that aren't quite mature yet, and as Capistrano sits on the boundary of where these problems come to light, it seems to fall to us to deal with it, and to educate people on what they ought to be doing.
Education is no problem, I really believe that the de-facto standardisation of Rails-like deploys (i.e timestamped releases, with common linked directories, and a symlink to the current active timestamp) is an excellent result for knowing what to expect in an environment where there's hundreds of ways to get Rails apps running, but it's still not as smooth a process as it could be.
I'm familiar with at least one project that's been re-written in Scala and Java because the previous version was prohibitively difficult to deploy as it was in RoR. (GrayLog2, to namedrop them)
> I'm also of the opinion that compiling assets in production as a part of your deployment process is insane, there's so much magic in the Rails asset pipeline that it's not uncommon to turn up bugs where tables don't exist, and the rails app can't initialize, or some javascript runtime environment isn't found which can leave your deployment in a broken state.
This is one of the pain points for me. Even when everything is setup, the asset compilation churns the disks and takes way too much cpu. I would rather do that on my local machine than disrupt the production server. I do a simple workaround for that:
namespace :deploy do
namespace :assets do
desc 'Run the precompile task locally and rsync to shared'
task :precompile, :roles => :web, :except => { :no_release => true } do
run_locally "rake assets:precompile"
run_locally 'rsync -e "ssh -i production.pem" --recursive --times --rsh=ssh --compress --human-readable --progress public/assets #{user}@#{host}:#{shared_path}'
run_locally "rake assets:clean"
end
end
end
# Dont recompile assets unless they hange
task :precompile, :roles => :web, :except => { :no_release => true } do
from = source.next_revision(current_revision)
if 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
I'm not entirely happy with it and don't even know if it's something I should be doing. I rarely change my assets, so this at least allows me to do quick deploys until an asset change comes. (shrug) It feels incredibly hacky.
For me, the more important thing was not compiling on a production box. Compiling on production box does lots of io and uses way too much cpu. I am ok with a slight delay in deploy due to assets compilation happening on my local machine.
I see a lot of people in this thread criticizing the assets pipeline. But I think it's a good idea with an implementation which is yet to mature. For now, it needs some work on my part(do I check in the assets, do I compile on production box, how do I ensure assets are only compiled when changed etc etc), but overall I am quite happy with the way it works.
My deployment process does this too. One thing to be careful of is to make sure you're not deploying a different revision than the one you are on locally. For instance, if you have uncommitted changes locally, they will be reflected in your assets but not in the rest of your deploy.
Yes. Different branch and uncommitted changes are an issue. Different branch can be solved by switching the branch if `git rev-parse HEAD != git rev-parse branch`. Uncommitted changes can be handled by `[[ -n $(git status -s)]]`(simply abort).
This is a very familiar pain point for me. IMHO many problems with RoR deployment stem from the fact that Ruby depends on so many native code extensions. It's pathetically easy to break things like therubyracer or nokogiri because some .so file was updated or is not installed. I'm guessing that this is done for performance issues with the Ruby interpreter, but wow, it really makes for portability nightmares. Add RVM on top of this and it's just insane.
As someone coming from Java (I largely switched from Java to Rails about a year ago) I find this tendency toward native code deps incredibly painful. Turns out there's a really good reason to demand "100% pure Java" libraries. One can always throw rocks at Maven or CLASSPATH hell, but I find that Ruby deploys tend to be much more problematic than Java.
Whatever you decide on I hope you get some relief. FWIW I have benefited greatly from your work on Capistrano, and sincerely appreciate your efforts.
I wonder if one solution wouldn't be to have an actual build enviroment that is neither development or production, but between the two. We have that where I work and asset compiling fit very naturally into where we compile the RPM (which is how we deploy, by necessity).
Exactly. Build on a staging system. Take a server (or a couple of them) out of LB, put new, already built stuff in. Put in back into LB, rinse, repeat until you have the new stuff everywhere. Don't actually build anything on a production server. Perfectly scriptable, possible to rollback (if you keep your releases tagged) and if you pay attention to monitoring you can even spot significant problems mid-deploy.