When using simple cache adapters MaxListenersExceededWarning is emitted. This has previously been investigated in #792 and #1128 but either it is a regression or did not account for highly asynchronous environments with 100's of parallel requests.
Unsure if this is best opened in either keyv or cacheable-request, but given it was declared solved in #1128 I've opened it here first.
Environment Info:
System:
OS: macOS 10.15.7
CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Binaries:
Node: 12.19.0 - ~/.nvm/versions/node/v12.19.0/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 6.14.8 - ~/.nvm/versions/node/v12.19.0/bin/npm
Browsers:
Chrome: 86.0.4240.198
Safari: 14.0
Got: 11.8.0
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [Keyv]. Use emitter.setMaxListeners() to increase limit
const got = require('got');
const client = got.extend({
cache: {
get: (key) => {
return undefined;
},
set: (key, value) => {
}
}
});
(async () => {
const promises = [];
for (let i = 0; i < 20; i++) {
promises.push(client('https://www.google.com', { method: 'HEAD' }));
};
await Promise.all(promises);
console.log('Done');
})();
Actually this isn't a memory leak.
But the code can be optimized anyway.
@szmarczak ah, so the listener is removed after handling is complete so this only occurs when you have more than 10 requests in flight at any one time?
Correct.
@szmarczak so how would you suggest proceeding because having many requests in flight at any one time is fairly normal use-case. Does the max listeners limit need raising? Warnings being emitted during normal operation scares the villagers, such as myself.
The workaround lies in the very title of the issue:
Use emitter.setMaxListeners() to increase limit
Simply pass a Keyv instance as the cache option. Just set cache.setMaxListeners(100000) and you're good to go.
@szmarczak I expected that too, but it doesn't. That's why I created this (by the way, thanks for helping chase this around).
const got = require('got');
const Keyv = require('keyv');
const keyv = new Keyv();
keyv.setMaxListeners(10000);
const client = got.extend({
cache: {
get: (key) => {
return undefined;
},
set: (key, value) => {
}
}
});
const keyvClient = got.extend({
cache: keyv
});
(async () => {
console.log('Simple cache client', 'start');
let promises = [];
for (let i = 0; i < 20; i++) {
promises.push(client(`https://www.google.com?${i}`, { method: 'HEAD' }));
};
await Promise.all(promises);
console.log('Simple cache client', 'end');
console.log('Keyv cache client', 'start');
promises = [];
for (let i = 0; i < 20; i++) {
promises.push(keyvClient(`https://www.google.com?${i}`, { method: 'HEAD' }));
};
await Promise.all(promises);
console.log('Keyv cache client', 'end');
console.log('Done');
})();
Output
paul@Pauls-iPad got-keyv % node test.js
Simple cache client start
(node:55811) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [Keyv]. Use emitter.setMaxListeners() to increase limit
(Use `node --trace-warnings ...` to show where the warning was created)
Simple cache client end
Keyv cache client start
(node:55811) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [Keyv]. Use emitter.setMaxListeners() to increase limit
Keyv cache client end
Done
It's because it creates another Keyv instance:
So I don't think there is any workaround at all for now :(
@szmarczak ok. Many thanks for the help with all of this!
Hello, I got the same issue Using native JS Map() object. What can I do ?
I am using got "got": "^11.8.0"
const cache = new Map();
export const https = new HttpsProxyAgent({
keepAlive: true,
maxSockets: 256,
proxy: 'http://plugin-gateway.platform:8081',
});
const product: IProduct = await got.get(`${apiUrl}/product/${productId}`, {
retry: 2,
cache: cache,
agent: { https },
headers: {
Authorization: apiPassword,
},
}).json();
Error :
(node:1) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [Keyv]. Use emitter.setMaxListeners() to increase limit
Up ?
Hi guys
I'm experiencing the same issue as described here. Does that mean there is no way to send many request parallel with GOT using cache? How would this be possible? Sorry about my ignorance if this sounds a stupid question and thanks for your help
Hello guys
I am experiencing this issue too. May be the work around kind of solution (or solid fix) could be added to got library itself?
It's because it creates another Keyv instance:
I'm facing issues for similar reasons, it's also registering an once error listener that gets cleared after response, which is ok-ish but it doesn't account for databases connection error (eg: replicas failover) which crashing the process and preventive over network fallback.
I think Got could also benefit from this, I've opened a PR about this at cacheable-request, @szmarczak are you also a maintainer of that lib? WDYT?
Most helpful comment
I'm facing issues for similar reasons, it's also registering an once error listener that gets cleared after response, which is ok-ish but it doesn't account for databases connection error (eg: replicas failover) which crashing the process and preventive over network fallback.
I think Got could also benefit from this, I've opened a PR about this at
cacheable-request, @szmarczak are you also a maintainer of that lib? WDYT?