jacquescrocker / jammit-s3

Extensions so you can use jammit with s3/cloudfront for your Rails app
http://documentcloud.github.com/jammit/
MIT License
124 stars 31 forks source link

Support for COMMIT_HASH in asset paths #13

Closed emk closed 8 years ago

emk commented 13 years ago

Thank you for your excellent gem!

This patch makes it a lot easier to use CloudFront, which is terrible about expiring existing assets, and it does so in a way that should be compatible with Heroku.

Please let me know if you have any questions or if you would like any changes. Thank you!

kmamykin commented 13 years ago

I contacted heroku re: COMMIT_HASH and they said it is unsupported at the moment. I would be hesitant to merge these changes into the master at the moment. Another approach is to use RAILS_ASSET_ID env var, which you can set to whatever during the deployment. I implemented this in https://github.com/kmamykin/jammit-s3

emk commented 13 years ago

That's too bad. Fortunately, nothing in this patch actually relies on Heroku, except for the documentation. Here's how I set up production.rb for use with Capistrano:

# Load our release-specific configuration from release.yml.
RELEASE_INFO =
  YAML.load(File.read(File.join(Rails.root, 'config/release.yml')))

# Enable serving of images, stylesheets, and javascripts from an asset server
config.action_controller.asset_host = "dsz6mnjgj82i1.cloudfront.net"
config.action_controller.asset_path = lambda do |asset_path|
  "/#{RELEASE_INFO['COMMIT_HASH']}#{asset_path}"
end

And in deploy.rb:

before 'deploy:update_code' do
  system 'bundle exec jammit' or raise "Can't compile assets"
  system 'bundle exec jammit-s3' or raise "Can't upload assets to S3"
end

after 'deploy:update_code' do
  # Save our release ID in a configuration file.
  run "echo COMMIT_HASH: #{COMMIT_HASH} > #{File.join(release_path, 'config/release.yml')}"
end

Right now, the master branch of jammit-s3 doesn't really work with CloudFront, because CloudFront invalidation is pretty complicated.

Any thoughts on how I should update this patch? Thank you for your feedback!

Cheers, Eric

kmamykin commented 13 years ago

Hi Eric, Thank you for submitting the patch. There are a few forks floating around that deal with CloudFront issue, I just need to find some time and merge it all together.

jacquescrocker commented 13 years ago

added support here. https://github.com/railsjedi/jammit-s3/commit/3dead946da96d94f33d05ed4e63e40785f8ab4a4 let me know if this approach works for you. thanks!

emk commented 13 years ago

Thank you for adding more CloudFront support!

Unfortunately, there are a number of problems with relying on CloudFront invalidation:

1) It may reportedly take up to 15 minutes to invalidate all the CloudFront caches around the globe (and Google charges for more than a certain number of invalidations per month). 2) It's non-atomic from the perspective of the end-user: They may get an older version of the site with a newer version of the JavaScript and CSS, or vice versa. 3) It doesn't play nicely with aggressive HTTP caching. For example, once I serve a script or a stylesheet, I would like it to be cached indefinitely with no more round trips to see whether it is valid.

Given these constraints, there's still an important need for some kind of content-based hashing. Done right, this assures that all files can be cached indefinitely, and the user will always get matched HTML/JS/CSS files.

Thank you for your work on Jammit S3!

Cheers, Eric

jacquescrocker commented 13 years ago

ah, excellent point. reopened pull request. we should come up with a solid solution to this. i dont use cloudfront at the moment so i'm not intimately familiar with it. i'd be happy to merge in your changes if you think you have a solid solution

simonoff commented 13 years ago

I think solution from emk excellent! But better use package_path config option of Jammit:

after 'deploy:update_code' do
  run "echo package_path: assets/#{COMMIT_HASH} > #{File.join(release_path, 'config/assets.yml')}"
  run 'bundle exec jammit'
  run 'bundle exec jammit-s3'
end
emk commented 13 years ago

On Mon, Apr 11, 2011 at 2:35 PM, railsjedi < reply@reply.github.com>wrote:

ah, excellent point. reopened pull request. we should come up with a solid solution to this. i dont use cloudfront at the moment so i'm not intimately familiar with it. i'd be happy to merge in your changes if you think you have a solid solution

Ideally, it would be nice to do something which Just Worked on Heroku, and other git-based deployment systems. We would need to find some piece of information which uniquely identified a specific version of the program, which could be embedded into a URL, and which we could easily and cheaply retrieve on both the development and the production machines.

The git commit ID is one obvious choice. The SHA1 sum of a given asset file would also work, though it's probably a lot more expensive to compute at runtime on the server, and it makes it harder to clean old junk out of CloudFront.

So I'd love to have some way to use either COMMIT_HASH, or (if that's not really what you want) something similar that I can compute using Ruby code and supply to Jammit S3 at runtime.

Many thanks for jammit-s3!

Cheers, Eric

simonoff commented 13 years ago

I make it like this:

desc "Make new jammit assets path based on commit hash"
task :jammit do
  run "echo \"package_path: 'assets/#{release_name}'\" >> #{current_path}/config/assets.yml"
  run "cd #{current_path}; bundle exec jammit"
  run "cd #{current_path}; bundle exec jammit-s3"
end

And run it before "deploy:restart". In release directories cleaning I can remove old asset releases on S3.

In this case I upload new assets and update if needed other static files. We not increase S3 storage data,but send invalidate request on updated files.

kmamykin commented 13 years ago

So I have an updated version here, which supports both asset invalidation and asset versioning. README updated with the info on how to configure, but basically comes down to one switch: use_cloudfront: invalidate or version. rake jammit:s3:heroku will Just Work (emk tm) on heroku. https://github.com/kmamykin/jammit-s3 I need someone to kick the tires and give a go/nogo for the merge to the jailsjedi repo.

JangoSteve commented 12 years ago

@kmamykin I can't get your branch to work. I keep getting:

Error message:
uninitialized constant Rails::Railtie
Backtrace:
#   File    Line    Location
0   /usr/local/rvm/gems/ruby-1.8.7-p302@rmsr/gems/activesupport-2.3.9/lib/active_support/dependencies.rb    466 in `load_missing_constant'
1   /usr/local/rvm/gems/ruby-1.8.7-p302@rmsr/gems/activesupport-2.3.9/lib/active_support/dependencies.rb    106 in `rake_original_const_missing'
2   /usr/local/rvm/gems/ruby-1.8.7-p302@rmsr/gems/rake-0.9.2.2/lib/rake/ext/module.rb   36  in `const_missing'
3   /usr/local/rvm/gems/ruby-1.8.7-p302@rmsr/bundler/gems/jammit-s3-2a7245027fa5/lib/jammit-s3.rb   12  

Does your fork not support Rails 2.3?

kmamykin commented 12 years ago

I have not tested on rails 2.3, and apparently it does not work. Feel free to submit a separate pull request. I am not actively using jammit-s3 anymore, switched to assets pipeline.

JangoSteve commented 12 years ago

@kmamykin cool thanks. Yeah same here, was just trying to retrofit this onto an old app I didn't feel like updating. I probably might as well upgrade it at this point.

emk commented 8 years ago

OK, this PR is almost half a decade old, so I'm assuming it's obsolete. :-) Closing it.