Uploaded image for project: 'Node.js Driver'
  1. Node.js Driver
  2. NODE-4845

Allocate ClientSession on cursor initialization instead of instantiation

    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      Current Behavior

      In the constructor for AbstractCursor, when no session is provided as an option, we create a ClientSession and assign it to our private kSession property on the cursor.

      This session is pinned to the cursor for the duration of the cursor's life.  Only once the is fully iterated, we clean up the session.

      Problem

      If the cursor is never iterated, the session will never be destroyed and will remain active in memory in the `activeSessions` set on the MongoClient.  This would be possible for any cursor command that does not iterate the cursor (FindCursor.count, for example).

      I believe this impacts shell, since shell supports `cursor.count()`.  My guess is that every shell find command returns a new cursor, so multiple cursor.counts() in a row would leak sessions.

      Acceptance Criteria

      Defer session creation until cursor initialization.  This ensures that no session is allocated until iteration has begun.  Currently, cursors must be manually cleaned up if partially iterated.  This change would tie the lifecycle of the cursor's session to our supported behavior for our cursors.

      Testing AC

      Seek to add tests similar to MongoClient resource leak tests, create find cursors, don't iterate them and don't close them, assert memory usage does not grow unbounded if the cursors are allowed to go out of scope and the garbage collector has had a chance to run. Our goal is to try and detect arbitrary changes to the cursor class that could lead to leaks caused by saving resources to the parent collection/db/client.

      Documentation

      • Add documentation about cursor clean-up expectations to explain, count, and any other async cursor methods that do not relate to the cursor lifetime
      • Document on find, aggregate, watch, listCollections, listSearchIndexes, listIndexes, and runCommandCursor when closing a cursor is and is not needed

      Example Reproduction

       

      import { MongoClient } from './src';
      
      const client = new MongoClient(process.env.MONGODB_URI!);
      
      async function main() {
        const collection = client.db('foo').collection('bar');
        const cursor = collection.find();  
      
        // do not iterate cursor
        await cursor.count();  
      
        // uncomment the following line to clean up all sessions on the client
        //   await cursor.toArray();
      }
      
      main()
        .then(() => {
          console.log(`number of active sessions on client: ${client.s.activeSessions.size}`);
          return client.close();
        });
       

       

       

            Assignee:
            Unassigned Unassigned
            Reporter:
            bailey.pearson@mongodb.com Bailey Pearson
            Votes:
            3 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated: