Search code examples
next.jsamazon-ecsaws-application-load-balancer

NextJs has sporadic issue when serving from a load balancer with multiple nodes


This is a problem where we get only when running on multiple nodes.

Our application is hosted on AWS ECS docker containers with Auto Scaling Group attached managed by an Application Load Balancer.

The NextJs application works fine when it only serves with one node. But to ensure high availability we need to server from multiple nodes. Since it has multiple build IDs, we added the following configuration to the next.config.js file

const nextConfig = {
  generateBuildId: async () => "default-build",
  experimental: {
    isrMemoryCacheSize: 0,
  },
};

module.exports = nextConfig;

The following issue occurs then enter image description here

The browser console error logs are as follows

Failed to load resource: the server responded with a status of 404(Not Found)

ChunkLoadError: Loading chunk 84 failed.
(error: http://replaced-this-url/_next/static/chunks/app/%5Blang%5D/layout-332c238ae51cc7a7.js)
    at d.f.j(webpack - 8b6d851d58492f7f.js: 1: 3285)
    at webpack - 8b6d851d58492f7f.js: 1: 1427
    at Array.reduce(<anonymous>)
        at d.e (webpack-8b6d851d58492f7f.js:1:1393)
        at self.__next_chunk_load__ (488-4c8bbce90f9d2c06.js:1:3713)
        at 488-4c8bbce90f9d2c06.js:9:5403
        at 488-4c8bbce90f9d2c06.js:9:5813
        at N (488-4c8bbce90f9d2c06.js:9:6016)
        at t (488-4c8bbce90f9d2c06.js:9:8912)

Uncaught Error: Minified React error #423; visit https://reactjs.org/docs/error-decoder.html?invariant=423 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
        at iv (2443530c-01613f55fe4aacb8.js:9:113059)
        at oR (2443530c-01613f55fe4aacb8.js:9:90030)
        at 2443530c-01613f55fe4aacb8.js:9:89879
        at oD (2443530c-01613f55fe4aacb8.js:9:89886)
        at ow (2443530c-01613f55fe4aacb8.js:9:87588)
        at ok (2443530c-01613f55fe4aacb8.js:9:86450)
        at E (488-4c8bbce90f9d2c06.js:25:1398)
        at MessagePort.C (488-4c8bbce90f9d2c06.js:25:1951)

ChunkLoadError: Loading chunk 84 failed.
        (error: http://replaced-this-url/_next/static/chunks/app/%5Blang%5D/layout-332c238ae51cc7a7.js)
        at d.f.j (webpack-8b6d851d58492f7f.js:1:3285)
        at webpack-8b6d851d58492f7f.js:1:1427
        at Array.reduce (<anonymous>)
            at d.e (webpack-8b6d851d58492f7f.js:1:1393)
            at self.__next_chunk_load__ (488-4c8bbce90f9d2c06.js:1:3713)
            at 488-4c8bbce90f9d2c06.js:9:5403
            at 488-4c8bbce90f9d2c06.js:9:5813
            at N (488-4c8bbce90f9d2c06.js:9:6016)
            at t (488-4c8bbce90f9d2c06.js:9:8912)
            window.console.error @ 488-4c8bbce90f9d2c06.js:1
Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

I know Enabling Stickiness solves this issue. But since this is a static web application, it's not the best practice as we need to ensure the load is balanced. Hence the issue should be sorted from application logic side

Dockerfile

ARG base_image_build="node:18.17.1"
ARG base_image_run="node:18.17.1-slim"

FROM ${base_image_build} AS builder
WORKDIR /opt/app
COPY . .

RUN yarn install --frozen-lockfile --production

FROM ${base_image_run} AS runner
ENV NODE_ENV=production
USER node
WORKDIR /opt/app

COPY --chown=node:node --from=builder /opt/app /opt/app
COPY --chown=node:node --from=builder /opt/app/node_modules ./node_modules
CMD ["yarn", "docker"]

yarn docker: yarn build && yarn start


Solution

  • when building the application in the container startup, it generates distinct .next folder for each node with different artifacts, leading this separation results in chunk not found errors. Renaming the filenames and chunks on the client side in the webpack configuration will be able to keep the same artifacts across all builds will helps to resolve chunk not found issue. Adding the following on next.config.js solved the chunk loading issue, and ultimately, solved the issue.

    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
        if (!isServer) {
          config.output.filename = 'static/chunks/[name].js';
          config.output.chunkFilename = 'static/chunks/[name].js';
        }
        return config;
      }