Maximum number of concurrent React renderers exceeded when using pipe()

Viewed 321

I have a React app with SSR that is running in Kubernetes. After a few days without restarting Pods I get this error: https://reactjs.org/docs/error-decoder.html/?invariant=304.

I use ReactDOMServer.renderToNodeStream and pipe() and according to the error:

This can happen if you are not properly destroying the Readable provided by React. Ensure that you call .destroy() on it if you no longer want to read from it, and did not read to the end. If you use .pipe() this should be automatic.

Here is my server renderer:

export function renderOnServer(res, controller) {
    return new Promise((resolve, reject) => {
        try {
            const index = controller.getIndexHTML();
            const view = controller.getView();

            const indexHTML = `<!DOCTYPE html>${ReactDOMServer.renderToStaticMarkup(index)}`;
            const chunks = indexHTML.split("{{STREAMED_CONTENT}}");
            
            const firstChunk = chunks.shift();
            const lastChunk = chunks.shift();

            res.write(firstChunk);

            const stream = ReactDOMServer.renderToNodeStream(view);
            stream.pipe(res, { end : false });
            stream.on("end", () => {
                res.write(lastChunk);
                res.end();
                resolve();
            });
        } catch(err) {
            reject(err);
        }
    });
}

I use pipe() but I also handle end event as seen in the code. Could it be the cause of the problem? Or should I focus on another part of the code?

Any help is appreciated. Thanks.

1 Answers

your code seems totally ok. Maybe it's some weird React library's issue. You can do following things:

  1. Update ReactJS library and NodeJS to the current version
  2. Try to destroy the stream in "end" callback function:
stream.on("end", () => {
   stream.destroy(); // but I think it is not necessary
   res.write(lastChunk);
   res.end();
   resolve();
});
  1. you should add stream.on("error", () => something to do) callback function

Or you can replace the renderToNodeStream calling with renderToString. It's not as memory efficient as using streams but safer in your case.

Related