-
Notifications
You must be signed in to change notification settings - Fork 152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setting "no-cache" for 404 files #245
Comments
Hi, thanks for your message. Sorry I haven't had time to look at this earlier. The issue you've identified is one of the things that's bothered me before about the whitenoise model, but I don't see a simple, neat way of fixing it. My assumption was that this would be quite a rare situation because usually the previous versions of the assets would already have been cached by the time the next deploy happens. But maybe you're clearing caches after you deploy or something like that. One really hacky approach I thought of would be a bit of middleware which catches 404s under STATIC_URL and then changes them to a redirect to the same URL but with I think if you'd had a bit of middleware which returned Thanks. |
Hi, Thanks for replying! No worries about it! You're right about previous versions being cached, but since the newer versions have different hashes in its file, there's no cache for those and the first time they're request might end up in a previous Django instance that will return 404 back to CloudFlare. Thanks for considering add a new middleware for this special case. I'll try to cook something up, try it on my code and share it here if that ends up working. I google'd and Heroku can do rolling deploys / zero downtime, and more and more apps are behind CF, so this issue will become more apparent in the future, I believe. Thanks again! |
One partial solution that could work for some applications would be to fall back to serving the "hash-less" version of the file whenever WhiteNoise returns a 404, making sure that the fallback response doesn't get cached. This relies on I haven't run this production, and there are many cases where this would not work (see below), but perhaps this can prove useful to someone. from whitenoise.middleware import WhiteNoiseMiddleware
from django.utils.cache import add_never_cache_headers
class WhiteNoiseWithFallbackMiddleware(WhiteNoiseMiddleware):
def __call__(self, request):
response = super().__call__(request)
if response.status_code == 404 and request.path.startswith(self.static_prefix):
fallback_path = self.get_name_without_hash(request.path)
request.path = request.path_info = fallback_path
fallback_response = self.process_request(request)
if fallback_response:
response = fallback_response
add_never_cache_headers(response)
# might also need `patch_cache_control(response, private=True)` if using Django < 3
return response Updating a static fileLet's say there is a static file called The currently deployed version of the application (Version A) has the file referred to as In the following, we assume that we are in the middle of the deployment, during the short interval where the two versions A and B are serving requests. If both requests are served by the same version, then everything is fine. If If Adding or removing a static fileIf a brand new file is added, then things are a bit trickier. The change will have to be made across two deploys: first a deploy where the new file is added, but isn't referred to anywhere; then a second deploy where the HTML is updated to refer to the new file. The steps are similar if a file is removed (i.e. remove the reference but keep the file, then remove the file in a subsequent deploy). This is similar to how database migrations have to be handled with rolling deploys, so hopefully the process should feel familiar for people working on such projects. Let's say a new file On the other hand, if the change is staggered across two deploys (A -> add new.js, no changes to index.html -> B -> add Problems with this approachThis would work best for files that are self-contained JS apps that don't rely too much on the surrounding HTML markup. If on the other hand the program is split across several files, then there could be some breakages when a mix of old and new versions which depend on one another are loaded together. For example, Thankfully any such glitches should be short-lived, and perhaps this is a good enough trade-off for your use case. Having the possibility that a request to |
@rafikdraoui really interesting take, thanks for sharing! Maybe I'll use your solution on my projects. |
Hi,
First of all, thank you very much for the time and effort you've put into this project!
I have what I believe is an uncommon setup: during deploy I have both new and old application servers working simultaneously (using k8s),
STATIC_URL = '/static/'
and everything behind CloudFlare.During a deploy that changes static files (such as when updating anything else compiled by webpack), due to the fact that old application code are still running while new pods are being brought up, if a page is loaded and routed to the new app server, it gets the new version and thus in the HTML there's a request to download the new version of the file (
css-$newhash.css
) but some of those static requests end up being served by old versions of the app code and that returns, obviously, 404. Now CloudFlare caches those 404 and every new page load is broken due that.I'm not using
collectstatic
because webpack already generates the files with hashes.I'm thinking on how to tackle this and I see two possibilities:
STATIC_URL
as the URL prefix and sets up ano-cache
.Thanks a lot!
Edit: for reference, here's the answer from CloudFlare telling to use
no-cache
on 404 pages to avoid this issue.The text was updated successfully, but these errors were encountered: