Can static assets be updated on a production server without a restart?

I am using Elixir releases. Every new release causes a production server restart. If I only update my static assets and cache_manifest.json, Router.Helpers.static_path/2 does not work with the newly uploaded assets. Is there a way of reloading cache_manifest.json without restarting the production server?

1 Like

i just spent some time digging into the source-code to find a solution, as this was bugging me also for the longest time.

starting from this github-issue “Reload static assets in production mode without rebooting server #992”
i figured out a solution which works for me:

❖ after calling mix phx.digest i run this to refresh the static-asset-paths:

Phoenix.Config.clear_cache(MyAppWeb.Endpoint)
Phoenix.Endpoint.Supervisor.warmup(MyAppWeb.Endpoint)

these commands might be helpful in debugging specific asset-paths:

MyAppWeb.Router.Helpers.static_path(MyAppWeb.Endpoint, "/css/app.css")

Phoenix.Endpoint.Supervisor.static_lookup(nil,"/css/app.css")

:ets.lookup( MyAppWeb.Endpoint, :cache_static_manifest_latest)[:cache_static_manifest_latest]["css/app.css"]
3 Likes

In my case, I ended up parting ways with the Phoenix way of digesting static assets. My solution uses xxHash for fingerprinting. The custom function that replaces Router.Helpers.static_path/2 can then look for updated versions of the file(s) that contain the static asset hashes in any way desired.

2 Likes

Can you share the custom function and how you implement and use the C library you shared to create the hash.

The static_path/2 replacement function has several others behind it. The approach is broadly as follows:

  1. Static asset hashes are created by calling an Elixir script containing the following (on Windows):
System.cmd("C:/my_path_to/xxhsum.exe", ["-H64", static_asset_path])
  1. Hashes are then stored in cssjs.ini (coupled with the app) and bulky.ini (uncoupled from the app), naming INI sections after file extensions and keys after filenames.

  2. When my app is started, ConfigParser.parse_file/2 parses hash data and transfers them to an ETS table, allocating one ETS table key per file extension.

  3. Wherever I need the static path, I pass the name and extension to a function that reads the hash from the ETS table. If (1) the hash is not found, (2) the file extension belongs to bulky.ini, and (3) a minute has elapsed since the last update, then bulky.ini is re-parsed to fetch any newly added hashes, and the ETS table is updated.

  4. Uploads to the server can thereafter involve everything except bulky assets, everything including bulky assets, or bulky assets alone.

This setup may not be very simple, but it does offer unlimited flexibility.

3 Likes