Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic databases causing memory leak #12520

Closed
1 task done
NajamShehzad opened this issue Oct 4, 2022 · 1 comment
Closed
1 task done

Dynamic databases causing memory leak #12520

NajamShehzad opened this issue Oct 4, 2022 · 1 comment
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary

Comments

@NajamShehzad
Copy link

NajamShehzad commented Oct 4, 2022

Prerequisites

  • I have written a descriptive issue title

Mongoose version

6.6.4

Node.js version

14.19.3

MongoDB version

5.0.13

Operating system

No response

Operating system version (i.e. 20.04, 11.3, 10)

Windows 11

Issue

I'm facing memory leak issue when using multiple databases
I have a use case in my application, for each user i'm create a separate databases
When user make the request I load its database and store its database connection in the server. First I was not saving the connection and calling useDb with each request but then it start eating more and more memory then I store the database connection in a map to reuse it.

The below function I use to get the database from the registeredDatabase Map

getCollection(_db: string, type: string){
  const database = this.registeredDatabase.get(_db);
  if (!database) {
    this.registerSingleDatabase(_db);
    const newDatabase = this.registeredDatabase.get(_db);
    return newDatabase.models[type];
  }
  return database.models[type];
}

And to register new database in the memory

registerSingleDatabase(_db: string) {
  this.registeredDatabase.set(_db, this.connection.useDb(_db, { useCache: true }));
  const currentDatabaseConnection = this.registeredDatabase.get(_db);
  if (currentDatabaseConnection) {
    Object.keys(TempModelName).forEach((key) => {
      currentDatabaseConnection.model(key, AllSchema[key]);
    });
  }
}

Is there any better way to handle dynamic databases with mongoose.
I try to debug and create multiple memory snapshots and it show Native connections that keeps inside the memory and Model objects that stay there even If I don't need to use them. Then eventually the Server dies because of low memory

@NajamShehzad NajamShehzad added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Oct 4, 2022
@vkarpov15 vkarpov15 added needs repro script Maybe a bug, but no repro script. The issue reporter should create a script that demos the issue and removed help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary help wanted labels Oct 19, 2022
@vkarpov15 vkarpov15 modified the milestones: 6.6.7, 6.6.8 Oct 19, 2022
@vkarpov15
Copy link
Collaborator

I can offer some high level suggestions, I'm not 100% certain how your app works, but I'll do my best to make some reasonable inferences.

Given that you're creating a new database per user, I can see why you would be experiencing constant memory growth. Connections stay open by default, you need to do a little extra work to allow GC to clean up unused connections automatically. You can use the following getConnection() function:

getCollection(_db: string, type: string){
  const database = this.connection.useDb(_db, {
    useCache: false, // <-- avoid caching to allow GC to clean up
    noListener: true // <-- makes `database` avoid registering event emitters on base connection, which allows GC to clean up
  })
  // Register models if necessary
  if (database.models[type] === undefined) {
    this.registerSingleDatabase(database);
  }
  return database.models[type];
}

Also, in order to allow GC to clean up unused connections, you should do database.deleteModel(/.*/) when you're done with database to remove any models. That should be sufficient to allow your database to get GC-ed.

We also advise using your own caching rather than useCache if you expect to have a large number of db handles - more than 10k or so. useCache works well when you're fine with keeping connections open for the entire server lifecycle, but if you're running out of memory and need to evict stale connections you shouldn't use useCache.

See following comments for more info:

@vkarpov15 vkarpov15 added help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary and removed needs repro script Maybe a bug, but no repro script. The issue reporter should create a script that demos the issue labels Nov 2, 2022
@vkarpov15 vkarpov15 removed this from the 6.7.1 milestone Nov 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help This issue can likely be resolved in GitHub issues. No bug fixes, features, or docs necessary
Projects
None yet
Development

No branches or pull requests

2 participants