Avoid Using Asset Sync
Last updated September 17, 2024
Using Asset Sync can cause failures. Heroku recommends using a CDN instead of asset_sync
whenever possible.
The asset sync gem uploads your assets (images, CSS, JavaScript) to a third party file store such as S3. From there, you can configure your application to tell browsers to download assets directly from S3. You should now use a CDN instead whenever possible.
Debugging
To be able to use the asset pipeline in production means you need to be able to debug the asset pipeline in production. If there is some failure or odd bug, often times the best way to debug is to reproduce the problem, this is usually done via opening up a bash session and attempting to re-generate assets
$ heroku run bash
~$ bundle exec rake assets:precompile
If you do this without asset_sync
any results are limited to your current dyno and will not effect your production app. However if you are using asset_sync
every time the task successfully runs the resultant files will be put on S3 which is being used by your production app.
This means while you are debugging and trying to find problems, perhaps by introducing new elements into files, such as modifying a style element:
~$ echo "body { background-color: red }" >> app/assets/stylesheets/application.css
~$ bundle exec rake assets:precompile
If you are not using asset_sync
this cannot cause problems. If you are using asset_sync
then a new application-<fingerprint>.css
will be generated and put onto S3, and there are potentially problems depending on how you’ve configured your app.
If you have asset sync set up to delete previously compiled files, then suddenly your production app doesn’t have access to the previous application-<old-fingerprint>.css
file. This would be bad, since the intent of the command was not to modify production, but to debug an issue.
Another asset_sync
option is to upload and use the manifest file from S3. If you have this enabled, then when the app restarts (via heroku restart
, after any config change, or once every 24 hours) then the new app will boot and since the new manifest file that you generated that says the application.css file you just created is the most recent, so it will start serving it to visitors to your site. This is bad as your production application assets may appear to change “at random” due to someone debugging assets.
These types of debugging mistakes can also happen locally where someone is using their production AWS credentials by mistake. If you are using asset_sync
then everyone on your team, and anyone who helps debug any problems such as a contractor, or a Heroku support staff must be aware of this gem in order to not mistakenly modify your production application.
Rollback
When you roll back your Heroku application to a previous release, by default your assets will not be re-compiled. This can cause problems if you are using the manifest sync option and you were expecting your assets to be rolled back along with your code. This behavior is unexpected, and can be confusing to anyone who does not immediately remember that their application utilizes asset_sync
.
Pipelines
If you are using pipelines to promote a staging slug to production and are serving assets via a CDN, then your asset pre-compilation will only be run once, on the staging app.
Using pipelines encourages the practice of always deploying to staging first to catch bugs. It also makes promotions to production very fast. The down side is that when an app is “promoted” to production the files on disk are moved to the new app and no new rake assets:precompile
is run. Because of this, assets compiled with a “staging” CDN url inside of them will be promoted to production:
body { background-image: url("http://staging-cdn.example.com/assets/smile-<fingerprint>.png") }
For many applications sharing a CDN between staging and production is surprising, however causes no problems. You can manually configure both to have the same “asset_host”. This works because even if the copy of the assets has been modified on the staging app, all assets are fingerprinted, and the “production” app will point browsers at the correct fingerprints. The staging app will serve up to 3 old copies of assets, and the CDN should keep assets cached indefinitely.
If you are not able to share a CDN between your production and staging app, then asset sync may be used as a stop-gap work around. To get it to work, you’ll need to use Release Phase, and add a release phase entry to your Procfile
:
release: rake assets:precompile
You’ll need to make sure that the “manifest” option is enabled. This works because on promotion the release phase will re-run and assets for your production app will be uploaded to your production S3 (or other file store) bucket. The reason you have to use the manifest option, is that all disk modifications in the release phase do not get stored in your application. If you don’t upload your manifest file, then when the app boots, it will use the manifest file from disk, which still points at all the assets that were generated from “staging”.
Be careful if you decide to use this work around. In the previous sections, warnings were made about the use of the manifest file option. It can make debugging and rollback both harder and more unpredictable. Please read the release phase documentation for more details on implementation and caveats.