FIX: Ensure theme JavaScript cache get consistent SHA1 digest (stable backport) #16669
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
(Stable backport of 7ed899f)
There is a couple of layers of caching for theme JavaScript in Discourse:
The first layer is the
javascript_caches
table in the database. When a themewith JavaScript files is installed, Discourse stores each one of the JavaScript
files in the
theme_fields
table, and then concatenates the files, compilesthem, computes a SHA1 digest of the compiled JavaScript and store the results
along with the SHA1 digest in the
javascript_caches
table.Now when a request comes in, we need to render
<script>
tags for theactivated theme(s) of the site. To do this, we retrieve the
javascript_caches
records of the activated themes and generate a
<script>
tag for each record.The
src
attribute of these tags is a path to the/theme-javascripts/:digest
route which simply responds with the compiled JavaScript that has the requested
digest.
The second layer is a distributed cache whose purpose is to make rendering
<script>
a lot more efficient. Without this cache, we'd have to query thejavascript_caches
table to retrieve the SHA1 digests for every singlerequest. So we use this cache to store the
<script>
tags themselves so thatwe only have to retrieve the
javascript_caches
records of the activatedthemes for the first request and future requests simply get the cached
<script>
tags.What this commit does it ensures that the SHA1 digest in the
javascript_caches
table stay the same across compilations by adding an orderby id clause to the query that loads the
theme_fields
records. Currently, wespecify no order when retrieving the
theme_fields
records so the order inwhich they're retrieved can change across compilations and therefore cause the
SHA1 to change even though the individual records have not changed at all.
An inconsistent SHA1 digest across compilations can cause the database cache
and the distributed cache to have different digests and that causes the
JavaScript to fail to load (and if the theme heavily customizes the site, it
gives the impression that the site is broken) until the cache is cleared.
This can happen in busy sites when 2 concurrent requests recompile the
JavaScript files of a theme at the same time (this can happen when deploying a
new Discourse version) and request A updates the database cache after request B
did, and request B updates the distributed cache after request A did.
Internal ticket: t60783.
Co-authored-by: David Taylor david@taylorhq.com