0

I have a flask + react application that is deployed on Google App Engine. Recently, I discovered that each time I deployed a new version to the GAE, my site would go down for a few hours, and several web pages cannot load correctly. I checked the console, the web application is trying to get the static files from the last version, which resulted in a 404 Error. Can anyone help me to find what the problem is?

Here is my app.yaml file:

runtime: python37
env: standard

default_expiration: "5m"

entrypoint: gunicorn -b :$PORT main:app --timeout 150

instance_class: F4

automatic_scaling:
  max_instances: 5
  min_instances: 1
  min_pending_latency: "5s"
  target_cpu_utilization: 0.75

inbound_services:
  - warmup

handlers:
  - url: /static/js/(.*)
    static_files: build/static/js/\1
    upload: build/static/js/(.*)
  - url: /static/css/(.*)
    static_files: build/static/css/\1
    upload: build/static/css/(.*)
  - url: /static/media/(.*)
    static_files: build/static/media/\1
    upload: build/static/media/(.*)
  - url: /(.*\.(json|ico))$
    static_files: build/\1
    upload: build/.*\.(json|ico)$
  - url: /
    static_files: build/index.html
    upload: build/index.html
  - url: /.*
    script: auto
Leon
  • 87
  • 7

2 Answers2

2

I am here to answer my own question. I seem to find the problem and how to solve it.

The main problem seems to be a caching issue. For the app.yaml settings, although the default expiration time is set to 5m, the url with path don't have the expiration set. For example, page www.example.com/about will have a different caching time than the js package. This means when a new build folder is deployed, the js packages have been changed, but the www.example.com/about page generated by your backend application is still the old version, and it will try to request the js package from the previous build foler. Thus, causing the 404 error.

The way to solve this is to set the expiration time for your response generated by your backend application. I am using the Flask environment, so the code for that is (credited to this answer)

response["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
response["Pragma"] = "no-cache" # HTTP 1.0.
response["Expires"] = "0" # Proxies.
Leon
  • 87
  • 7
0

the web application is trying to get the static files from the last version

So are these files that were removed in your new version that you just deployed?

In general, it sounds like your problem has to do with stale browser caches. I wouldn't remove static assets from your deployed app right away specifically for this reason.

I see you're using ReactJS. Are you using the features that combine all the js and css into a single file whose name contains a hash? This should help with cache-busting.

The part that's confusing is that you said it would go down for a few hours. You have default_expiration: "5m" in your app.yaml so a few hours sounds a bit extreme. Are you not doing a hard reload (or even a full reload) when you are trying to check out your changes in your browser?

Alex
  • 4,510
  • 8
  • 24
  • This is the thing I am confused about. I did not delete anything. What I have done was deployed a new version and migrate all the traffics to the new version. I set the expiration to 5 minutes to prevent caching issues. I have also tried hard reloads ```shift + F5``` but it did not work either – Leon Feb 17 '21 at 06:56
  • If you didn't delete anything, then what do you mean by `"static files from the last version"`? Because that made it sound like these files are no longer required for the new version. It would be good to see a couple examples of these 404s and compare them to the files in your project directory. – Alex Feb 17 '21 at 22:41
  • When I deploy a new version, I would deploy a new build folder generated by the ```npm run build```. So, for example, the previous build folder would have a ```main.12345.js``` package, and the new build folder would have a ```main.67890.js``` package. When I deployed the new folder, usually, the website should get the ```main.67890.js``` package, but instead, it was trying to get ```main.12345.js```. When I say I didn't delete anything, I mean I didn't delete anything from the app engine cloud buckets. – Leon Feb 18 '21 at 06:24
  • What I do not understand is why it is trying to obtain the previous package. In this way, this seems to be a caching issue, but ```default_expiration``` is set to 5 minutes, which in theory should prevent this problem – Leon Feb 18 '21 at 06:29