JoeSlav
JoeSlav

Reputation: 4815

MongoDB and PHP Library Cursor Timeout

While using official MongoDB's PHP Library (https://docs.mongodb.com/php-library/master/tutorial/install-php-library/), how to set the cursor timeout as infinite? I read mixed documentation and it's often hard to understand if it refers to the old PHP Driver or the new one (which I am talking about).

For instance:

$cursor = $col->find();
foreach ($cursor as $document) {
   // slow code..
}

How to prevent the cursor from timing out (see error below) and making sure the cursor is closed afterwards without any memory leaks?

Fatal error: Uncaught MongoDB\Driver\Exception\RuntimeException: 
cursor id 123456789 not found in /var/www/html/code.php:1

There are some similar questions here (like this) but it seems we lack a definite reference.

Upvotes: 2

Views: 2040

Answers (1)

Wan B.
Wan B.

Reputation: 18835

cursor id 123456789 not found in /var/www/html/code.php:1

Typically this is because the application is spending too long between getMore commands. In other words, the cursor returns a number of records on the first iteration and the loop takes a long time before it requests more records.

$cursor = $collection->find( [ 'field' => 'foobar'] );
foreach ($cursor as $document) {
    // long running processes (slow)
}

Cursors have a timeout on the server, after ~10 minutes if the client has not sent any commands to the server it will be closed due to inactivity. In the case above, when it's requesting for the next batch, the cursor has been killed resulting in the error message cursor id not found.

Some tried to disable the cursor timeouts by setting noCursorTimeout:true on the cursor. Although this is not recommended, because you may end up with a cursor that lives forever (zombie) when there's an issue with getMore results returning from the server. i.e. cursors with noCursorTimeout may remain alive on the server long after the client disconnected.

There are a couple of possible solutions:

  • Decrease cursor.batchSize(). This is because reducing the number of records per batch reduces the cursor inactivity. i.e. Previously 100 records processed for 15 minutes, now it's only 50 records for 7.5 minutes.

  • Manually create a session i.e. PHPLIB MongoDB\Client::startSession(). Then pass this as a session option on the queries. At regular intervals during the long-running iteration, perform some other database interaction using the same session i.e. ping the server. This will keep the session active (30 minutes timeout); however, it will do nothing to keep the cursor alive, so you may combine this with the use of noCursorTimeout.

Upvotes: 2

Related Questions