reactjsamazon-web-servicesaws-code-deploy

How to update react apps behind an AWS load balancer without 404 due to changing hash on main.js?


I'm deploying a react-app with AWC CodeDeploy, the following structure is generated by npx create-react-app npm build

/var/www/my-website
.
├── asset-manifest.json
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
├── robots.txt
└── static
    ├── css
    │   ├── main.2be1a5a0.css
    │   └── main.2be1a5a0.css.map
    ├── js
    │   ├── 787.28cb0dcd.chunk.js
    │   ├── 787.28cb0dcd.chunk.js.map
    │   ├── main.77918f81.js
    │   ├── main.77918f81.js.LICENSE.txt
    │   └── main.77918f81.js.map
    └── media
        ├── ...

The generated index.html looks like this

<!doctype html>
<html lang="en">
   <head>
      <meta charset="utf-8"/>
      <link rel="icon" href="/favicon.ico"/>
      <meta name="viewport" content="width=device-width,initial-scale=1"/>
      <meta name="theme-color" content="#000000"/>
      <meta name="description" content="Web site created using create-react-app"/>
      <link rel="apple-touch-icon" href="/logo192.png"/>
      <link rel="manifest" href="/manifest.json"/>
      <title>React App</title>
      <script defer="defer" src="/static/js/main.77918f81.js"></script>
      <link href="/static/css/main.2be1a5a0.css" rel="stylesheet">
   </head>
   <body>
      <noscript>You need to enable JavaScript to run this app.</noscript>
      <div id="root"></div>
   </body>
</html>

The EC2 AMI is configured with nginx

    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /var/www/my-website;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }

Now when running AWS CodeDeploy behind an AWS Load Balancer with either in-place or blue/green deployment, the situation occurs that for some time (until in-place is done or blue/green deregistered all the old instances) some instances serve the new version and some the old version.

Now the following issues comes up:

  1. HTTP Request is routed to InstanceOld1 with index.html with <script defer="defer" src="/static/js/main.hash1.js">
  2. InstanceOld1 tries to load /static/js/main.hash1.js via the load balancer with a HTTP call to http://abc-alb-xyz.eu-central-1.elb.amazonaws.com/static/js/main.hash1.js
  3. The load balancer distributes the call to InstanceNew1, which does not know main.hash1.js but only main.hash2.js, so it returns a 404

Same case also applies the other way around. It only works when all fetches happen to hit instances with the same version deployed.

Is there any way to work around this? E.g. not going through the load-balancer but load the main.js and main.css locally?


Solution

  • Took me quite a while to troubleshoot this issue...

    But I resolved it by enabling Sticky Session in the Target Group I use for the react app.

    Now a request for index.html will have AWS cookie headers. This ensures all subsequent requests for static files will be served from the same instance.

    Target Group Sticky Session