Skip to content

Instantly share code, notes, and snippets.

@schneems
Last active June 19, 2021 00:12
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save schneems/9374188 to your computer and use it in GitHub Desktop.
Save schneems/9374188 to your computer and use it in GitHub Desktop.
I hate asset_sync

A not politically correct assertion of my feelings towards a piece of software:

Note: Repetition builds cynicism, asset_sync isn't bad, but when an asset problem cannot be solved via support it gets escalated to me. Often times someone using asset_sync the problem is due to their use of the library and not from Heroku.

Backstory

The asset sync gem uploads your assets (images, css, javascript) to S3. From there you can either point browsers to the copy on S3 or use a CDN + the S3 bucket. It's a good idea, and solved a problem at one time.

It is no longer needed and you should now use https://devcenter.heroku.com/articles/using-amazon-cloudfront-cdn instead. So rather than copying your assets over to S3 after they are precompiled the CDN grabs them from your website instead. Here's some reasons why it's better.

Begin Rant

Cannonical Assets

I like Ruby, and I like Rails. The concept of keeping your code DRY is more than good practice it allows you to have single authoritive places of information. If you need to change that information you change it in one place and that's it. With asset_sync we're saying that although our "cannonical" copy of assets is in our source control, we're now relying on a 3rd party store of assets. What happens if someone has a failed deploy after assets get synced, what if someone modifies a file in the S3 bucket? Instead of fixing one copy of assets now you must fix two.

Deploy Determinism

If I'm debugging on my app inside of a dyno heroku run bash and I run rake assets:precompile this doesn't just modify my local copy, it actually modifies the copy on S3 as well. This goes back to cannonical stores, it can be bad. All your assets are screwed up and you don't know why. The sync part of asset_sync can also fail if S3 is down, or there's a glitch in the network. What if you only write part of a file, or only half of your assets are synced. These things happen

Do more with less

Now that you can have a CDN dynamically grab assets from your website there is no reason to add an extra step into the process. You 100% should be using a CDN as Ruby is horrible for serving assets, and S3 is only slightly better. If I asked you to move a bag of cement from a car to a construction site, you probably wouldn't feel very much like carying it to virgina first. This is essentially what you're doing when you're using asset_sync. It's not a bad step, but it's not a necessarry step either.

End Rant

Using asset sync can cause failures, is difficult to debug, un-needed, and adds extra complexity. Don't use it. Instead use https://devcenter.heroku.com/articles/using-amazon-cloudfront-cdn

I appreciate the authors of the software and everything asset_sync has allowed developers to do in the past. Now it's not needed so please don't use it.

ktksbye

@schneems

Comments

Comments on gists don't send notifications. You're basically shouting into the ether :(

@pwim
Copy link

pwim commented Aug 12, 2015

asset_sync may not be the strategy for Heroku. However, it is useful in some deployment configurations. For instance, we're using AWS OpsWorks.

With OpsWorks, when you deploy, the servers don't restart at the same time. This meant we sometimes had Server A running new code, but Server B running the old code. When Server A received a request, it responded with a reference to the new asset. This asset would be fetched via Cloudfront, which might then fetch it from Server B. As the deploy hadn't completed on Server B yet, it would respond with a 404. asset_sync solved this problem for us.

With our strategy, the assets get built and pushed to S3 via our CI. It's only possible for us to deploy after the CI has passed (including this upload step), so we've never had a problem with assets being half uploaded. We're also using the asset hash feature of Rails, so we can have multiple versions of the same assets in the same s3 bucket. One side benefit of this strategy is that it shortens deploy times, as we don't need to run the precompile rake task on deploy.

I understand that your article was written from the perspective of Heroku support. I just wanted to provide a counter example where the asset_sync gem is still useful.

@tpsrep0rts
Copy link

I'm looking into asset_sync for the sam reason that @pwim mentioned. You also gave some mis-information here in your article:

"You 100% should be using a CDN as Ruby is horrible for serving assets, and S3 is only slightly better" - serving assets is what S3 was made to do. While it doesn't scale nearly as well as a full CDN does, downloading static content from your deployment causes request processing threads to remain occupied doing tasks that require no dynamic computation. This is not what you want your ruby threads doing.

As @pwim described above, batch-based deploys can cause inconsistencies across your web nodes - making it impossible to reliably serve assets from your web tier mid-deploy.

@schneems I think it would be useful for you to explore how different production deployment strategies work before making claims that such a feature has no purpose.

@shaneog
Copy link

shaneog commented Oct 20, 2015

@pwim and @tpsrep0rts, how do you deal with dynamically serving gzipped content from S3? Since CloudFront/S3 doesn't dynamically serve the appropriate compressed/uncompressed asstes based on the browser's support for it in the request header

@dgilperez
Copy link

+1 on @shaneog concern

@damianlegawiec
Copy link

@Janther
Copy link

Janther commented Feb 14, 2016

Also there is a configuration option in AssetSync which only uploads the gzipped version of your assets to S3 and therefor to CloudFront.

AssetSync.configure do |config|
  # Automatically replace files with their equivalent gzip compressed version
  config.gzip_compression = true
end

@paulodeon
Copy link

https://devcenter.heroku.com/articles/using-amazon-cloudfront-cdn is not a complete solution as far as I can see. It doesn't describe at all how to set up the cloudfront distribution

@jstewart
Copy link

https://devcenter.heroku.com/articles/using-amazon-cloudfront-cdn is not a complete solution as far as I can see. It doesn't describe at all how to set up the cloudfront distribution

The AWS documentation is adequate. Basically, you set up a distribution which pulls from your server (serving static assets) as an origin. I just did this today and it was fairly simple. Bye, bye asset_sync!

@paulodeon
Copy link

What wasn't clear to me from the linked article is that the origin of the distribution is in fact the URL of your app. Once I realised that everything slotted into place. It is a complete solution and no need for asset_sync. Apologies for the FUD!

@KevinColemanInc
Copy link

we're saying that although our "cannonical" copy of assets is in our source control, we're now relying on a 3rd party store of assets

No, that is not typically how rails works. You don't commit the compressed assets to git, otherwise everytime you build them, your git history will be full of useless diffs (or new files if you use the checksum in the filename).

What happens if someone has a failed deploy after assets get synced

Nothing? don't delete the old assets and rollback the code.

What if someone modifies a file in the S3 bucket?

What if someone ssh's onto your ec2 box and modifies the source code? Don't do that. AWS has IAM roles that you can configure so that only the CI server has permission to modify s3 and your ec2 box.

Instead of fixing one copy of assets now you must fix two.

Why are you fixing things outside of git? Are you saying you ssh onto each server and modifying the code? S3 would be a single place where your assets are stored. If you have multiple web servers / dynos, then you have multiple locations of your assets.

If I'm debugging on my app inside of a dyno heroku run bash and I run rake assets:precompile this doesn't just modify my local copy, it actually modifies the copy on S3 as well.

How is this any different if you ran User.delete_all in production and you get mad when you lose your dyno modifies your postgres database?

The sync part of asset_sync can also fail if S3 is down, or there's a glitch in the network.

What if your server is down? Do you want all of your images (like in emails or direct links) to fail too?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment