cloudant / nodejs-cloudant

Cloudant Node.js client library
Apache License 2.0
255 stars 90 forks source link

Token refreshment memory-leak #419

Closed vmatyus closed 4 years ago

vmatyus commented 4 years ago

Checklist

Description

There is a memory leak when the client is instantiated inside a http request.

var Cloudant = require('./cloudant');
const http = require('http');

const server = http.createServer((req, res) => {
  var cloudantBasic = Cloudant({
    //account setting
    plugins: 'cookieauth'
  });

  async function getDbList() {
    return cloudantBasic.db.list();
  }

  getDbList().then(result => {
    res.statusCode = 200;
    res.end(JSON.stringify(result) + '\n');
    console.log('####test success');
  }).catch(err => {
    res.statusCode = 401;
    res.end(err.error + '\n');
    console.log('####test failed', err);
  });
});

server.listen(3000);
console.log('Server listening to port 3000. Press Ctrl+C to stop it.');

In this case when the server receives a request it will instantiate a client and after the response arrived all the request that went out toward Cloudant remained in the memory.

Approach

The default CloudantClient has the keepAlive option turned on and thank to this the opened sockets remain open and the last sent requests remain in the memory. So the memory could have been cleared when every socket had been closed. The current library supports only singleton usage. If it is not followed by the user there will be memory leak in the application. However, to mitigate the problem I used bind functions to remove several references from the memory and created a specific Agent for token refreshment, where the keepAlive is set to false. This way the token refreshment requests will be closed when the request is completed.

Mainly modified components: TokenManager, CoockieTokenManager, IAMTokenManager.

The above code sample was executed with the previous library and the current version. I sent 8 request to see the memory consumption: --- prev now diff
Request speed 7087 ms 7232 ms +200ms
after 8 request 8.8 MB 8.9 MB +0.1MB
5 minutes later 8.1 MB 7.8 MB -0.3MB

After 5 minutes more memory could be freed up by the Garbage Collector.

Schema & API Changes

Not changed.

Security and Privacy

Not changed.

Testing

Updated 1 test case:

vmatyus commented 4 years ago

A suggestion of usage about Cloudant client was added in this https://github.com/cloudant/nodejs-cloudant/pull/420