[BUG] memory leak caused by overmind during SSR when using createOvermindSSR
See original GitHub issueUPDATE 29 September 2020: We have discovered a memory leak.
On our server we use nodejs + express + server side rendering with overmind.
During SSR we have several functions initialize
, each one calls 1-3 effects.gql.queries.someGQLAction
.
Example:
export const initialize = withCatchDuringInitializeSSR(
async ({ state, effects }: SSRConfig) => {
const productsResponse = await effects.gql.queries.getProducts()
const products = overmindNormalize(
productsResponse.products,
"id"
);
state.comet.products.data = products;
},
"comet"
);
This effect is based on Overmind graphql addon
Once we deployed the code we noticed memory leaks reflected in our memory charts:
investigating with the help of heap profiler over consecutive snapshots we noticed that memory is held by one function:
it seems this function is the source of the leak. We don’t know exactly why. Here is the stack:
- our initialize.ts function with effect call
- overmind-graphql internals
graphql-request/src/index.ts --> GraphQLClient.prototype.request
graphql-request/node-modules/node-fetch/lib/index.js
json()
json() looks like:
json() {
var _this2 = this;
return consumeBody.call(this).then(function (buffer) { // <--- leak is caused by this function
try {
return JSON.parse(buffer.toString());
} catch (err) {
return Body.Promise.reject(...));
}
});
},
overmind-graphql 5.0.2 uses old version of graphql-request 1.8.2 (last 3.1.0), that in turn uses cross-fetch 2.2.2 (last 3.0.6) and cross fetch uses node-fetch 2.1.2 (last 2.6.1)
I believe if overmind-graphql updates graphql-request
to the latest version problem can vanish.
Probably this PR https://github.com/cerebral/overmind/pull/447 can be just merged?
UPDATE 1 October 2020: We discovered the source of the leak. It is overmind itself, not the dependency. Not sure why heap profiler shows function from node-fetch as a bottleneck, probably because objects that are held in memory are coming from this function.
Overmind places Symbols into objects each time we render page on the server. If we supply config
to createOvermindSSR
it adds symbols there and since config
is a global object it holds Symbols and Symbols hold references to objects which are not needed once rendered page sent back to client. Garbage collector can’t free them up.
it also happens if let’s say I have global constant:
export const PRODUCTS = { product_1: { array_1: [] }, product_2: { array_2: [] } }
and then during SSR I place it into state:
state.products = PRODUCTS
then Overmind pollutes this global constant with Symbols on each server page render which leads to memory leak.
If it is still not clear @christianalfoni I will try to provide reproducible demo later once I have time.
UPDATE 1 October 2020:
I created small repo with reproduction of the problem: https://github.com/SergeiKalachev/overmind-ssr-leak-demo
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:11 (7 by maintainers)
Top GitHub Comments
Great! Thanks for reporting 😄
@christianalfoni sorry for the late reply. I had a chance to test it. I upgraded to the version
27.0.0
and removed my workaround for avoiding memory leak. It seems the memory leak is no longer there:Chart looks quite smooth. It goes slowly up but I think it will reach some point and stop at it (based on the data for previous days). Thank you very much for the fix!