Rake assets:precompile without database

I noticed that the task rake assets:precompile requires a database connection: this means that the task can only be run at “run time” (after deployment) as opposed to “build time” (while building the container image). Since the task is very expensive in terms of running time, this can be annoying.

Not being a Ruby/Rails developer, I did some research and found that this behavior could be disabled until Rails 4, and afterwards developers have been resorting to some hacks (null database connection). The latter of course requires intimate knowledge of the application, in order to avoid breaking anything.

While searching for a better solution I found this commit which seems similar in spirit. So my questions are:

  • are the developers already working on the matter, or are there technical reasons why this cannot be done?
  • if some parts of the task indeed require the database connection, would it be feasible to split the task into two (or more), so that some work (e.g. compiling locales, minifying JS and CSS) can be done at build time?
  • is there a known workaround at this moment (e.g. “null database” as mentioned above)?
1 Like

We store the themes in the database (they are edited in the admin UI) so the CSS is inside PostgreSQL so you need the database connection at build time to be able to precompile those.

4 Likes

Thank you for the information!

Would it be thinkable to implement the build of locales separately (to be run at build time)?
Also, I can imagine that some environments (it is so for me at least) might not want to allow changing themes: would it be possible to provide an alternative storage for CSS in this case?

1 Like

We did discuss the idea of a switch that would disable the whole Customization UI, allowing the CSS files to be compiled in build time and uploaded to object storage during build (aka the same as the JS core / plugins).

However, that is a very niche case, that would only appeal to enterprise-y deployments while providing zero value to 99% of the communities on the web. So that isn’t in our roadmap and it is a pretty hard sell to put work on this over developing new features or performance work.

Can you tell us more about your environment and use case?

4 Likes

Good to know that the idea has already been discussed. I do understand that the amount of work for the change is probably too large to be justifiable.

In my case, discourse will be associated to a pre-existing website, so there will be a fixed custom theme to match the one of the website: it would not make sense to change it dynamically.

Oh I meant the use case for you to not be able to connect to the database on “build time”.

2 Likes

Oh: well, when I build the image, I work on my development laptop. The image is then pushed to a repository, and the final system (VPS on DigitalOcean) pulls it from there.

The database sits in a volume on the VPS, so it cannot be updated on my laptop: this would require me to stop discourse, rsync the database to my laptop, build and push the image, and finally restart discourse…

2 Likes

So you are running the database and the application all inside one droplet?

In that case sticking with our official install guide, which results in a droplet with application and database in the same droplet will give you a fully functional site, that can be updated from the web interface and optionally from the command line with a full image rebuild.

4 Likes

If by this you mean “directly on the host”, then no. They are running in a container, specifically a podman container. Ideally, I would split the container into multiple ones (one for discourse, one for postgres, one for redis…) but this connects with the issue that we are discussing, so I am still unsure on the proper course of action.

Seems unsafe to me. I generally test the containers in my development environment before deploying to production. Further, ideally containers should be read-only.

You can split those containers and then run the image bootstrap process in another, short-lived droplet. Since droplets are charged hourly that will be cheap. You can even leverage droplet private networking between the database container host and the “build” container host.

2 Likes

Hehe, thank you for the idea, but that starts to be complicated. Furthermore, it wont solve the problem, because we still have to stop discourse and wait for the bootstrap process, or there might be inconsistent data.

Seems like we will need to live with a long downtime (5-6 minutes for migration and precompilation) on upgrade. Still, I would appreciate if you guys could keep a low-priority issue in the tracker, maybe with a link to this topic.

Thank you, and keep up the good work!

No this is not the case.

Should only be “a few seconds” versus 5-6 minutes, but you need dedicated data and web containers. It depends what you want to prioritize.

Also per benchmarks rebuilding on a fast server should be ~3 minutes.

3 Likes

Good to know, thank you. In this case, I will definitely split the containers, which is a better architecture anyway.

However, I fail to see how this makes a difference? If I am not mistaken, all containers will share all host CPUs (unless configured otherwise), so processes should be run in parallel in both cases. Am I missing something?

Your old container will be running while the new one is bootstrapping. Then you can quickly switch off the old one and start the new one, so downtime will be shorter.

5 Likes