Docs Menu

Docs HomeDevelop ApplicationsPython DriversPyMongo

Limit Server Execution Time

On this page

  • Overview
  • timeout() Method
  • Nested Timeout Blocks
  • Thread and Task Safety
  • timeoutMS Connection Option
  • Handling Exceptions
  • Troubleshooting
  • ServerSelectionTimeoutError
  • NetworkTimeout
  • ExecutionTimeout
  • WTimeoutError
  • BulkWriteError
  • API Documentation

When you use PyMongo to perform a server operation, you can also limit the amount of time the server has to finish this operation. To do so, specify a client-side operation timeout. The timeout applies all steps needed to complete the operation, including server selection, connection checkout, serialization, and server-side execution. When the timeout expires, PyMongo raises a timeout exception.

You can specify a timeout in two ways: by using the timeout() method or by using the timeoutMS connection option.

To specify a timeout in your code, call the timeout() method and pass it the timeout length, in seconds. You must call the timeout() method in a with statement, as shown in the following example:

with pymongo.timeout(10):
collection.insert_one({"name": "Yngwie"})

In the preceding example, if the insert operation doesn't finish within 10 seconds, PyMongo raises an error.

The timeout you specify applies to all operations inside the with block. In the following example, the insert and find operations must both finish within a total of 10 seconds:

with pymongo.timeout(10):
coll.insert_one({"name": "Yngwie"})
coll.find_one({"name": "Yngwie"})

When execution enters a nested timeout block, the outer timeout is paused. When execution exits the nested timeout block, the previous timeout resumes.

Important

A nested timeout block can shorten the deadline of an outer timeout block, but it can't extend it.

The following example shows how to use nested calls to the timeout() method:

1with pymongo.timeout(5):
2 collection.find_one()
3 with pymongo.timeout(3):
4 collection.find_one()
5 collection.find_one()
6 with pymongo.timeout(10):
7 collection.find_one()
8 collection.find_one()

In the preceding example, the code performs the following steps:

  • Line 1: Creates a five-second timeout block.

  • Line 2: Calls the find_one() method inside the five-second timeout block. The server must
    complete this operation within the five-second timeout.
  • Line 3: Creates a nested three-second timeout block.

  • Line 4: Calls the find_one() method inside the three-second timeout block. The server must
    complete this operation within three seconds.
  • Line 5: Calls the find_one() method outside the three-second timeout block. The server must
    complete this operation within the original five-second timeout.
  • Line 6: Creates a nested ten-second timeout block.

  • Line 7: Calls the find_one() method inside the ten-second timeout block. A nested timeout
    block can't extend an outer timeout block, so the server must complete this operation within the original five-second timeout.
  • Line 8: Calls the find_one() method outside the ten-second timeout block. The server must complete this operation within the original five-second timeout.

The timeout() method is thread-safe. The timeout applies only to the current thread, and multiple threads can configure different timeouts in parallel.

The timeout() method is also asyncio-safe. The timeout applies only to the current Task, and multiple Tasks can configure different timeouts at the same time.

The following example shows how to use the timeout() method with Motor, the MongoDB Python driver for asynchronous applications:

import motor.motor_asyncio
client = motor.motor_asyncio.AsyncIOMotorClient()
coll = client["test-db"]["test-collection"]
with pymongo.timeout(10):
await coll.insert_one({"name": "Yngwie"})
await coll.find_one({"name": "Yngwie"})

To specify a timeout when connecting to a MongoDB deployment, set the timeoutMS connection option to the timeout length, in milliseconds. You can do this in two ways: by passing an argument to the MongoClient constructor or through a parameter in your connection string.

The following code examples use the timeoutMS option to specify a timeout of 10 seconds:

If you specify the timeoutMS option, PyMongo automatically applies the specified timeout to each server operation. The following code examples specify a timeout of 10 seconds, then call the insert_one() and find_one() methods. To see how the timeoutMS option compares to using the timeout() method, select the corresponding tab.

Important

timeout() Overrides timeoutMS

If you specify the timeoutMS option, then call the timeout() method in your code, PyMongo ignores the timeoutMS value inside the timeout block:

client = MongoClient("mongodb://localhost/?timeoutMS=10000")
coll = client["test-db"]["test-collection"]
coll.insert_one({"name": "Yngwie"}) # Uses the client's 10-second timeout
# pymongo.timeout overrides the client's timeoutMS.
with pymongo.timeout(20):
coll.insert_one({"name": "Yngwie"}) # Uses the 20-second timeout
with pymongo.timeout(5):
coll.find_one({"name": "Yngwie"}) # Uses the 5-second timeout

When a server operation exceeds the specified timeout, PyMongo raises a timeout exception and sets the PyMongoError.timeout property to True.

The following code example shows one way to handle a timeout exception. Inside the except block, the code checks the timeout property to determine whether the exception was caused by a timeout.

try:
with pymongo.timeout(10):
coll.insert_one({"name": "Yngwie"})
time.sleep(10)
# The deadline has now expired. The next operation will raise
# a timeout exception.
coll.find_one({"name": "Yngwie"})
except PyMongoError as exc:
if exc.timeout:
print(f"block timed out: {exc!r}")
else:
print(f"failed with non-timeout error: {exc!r}")

The following sections describe errors you might see when using timeouts.

This error indicates that the client couldn't find an available server to run the operation within the given timeout:

pymongo.errors.ServerSelectionTimeoutError: No servers found yet, Timeout: -0.00202266700216569s, Topology Description: <TopologyDescription id: 63698e87cebfd22ab1bd2ae0, topology_type: Unknown, servers: [<ServerDescription ('localhost', 27017) server_type: Unknown, rtt: None>]>

This error indicates either that the client couldn't establish a connection within the given timeout or that the operation was sent but the server didn't respond in time:

pymongo.errors.NetworkTimeout: localhost:27017: timed out

This error might indicate that the server cancelled the operation because it exceeded the given timeout. Even if PyMongo raises this exception, the operation might have partially completed on the server.

pymongo.errors.ExecutionTimeout: operation exceeded time limit, full error: {'ok': 0.0, 'errmsg': 'operation exceeded time limit', 'code': 50, 'codeName': 'MaxTimeMSExpired'}

It also might indicate that the client cancelled the operation because it wasn't possible to complete it within the given timeout:

pymongo.errors.ExecutionTimeout: operation would exceed time limit, remaining timeout:0.00196 <= network round trip time:0.00427

This error indicates that the server couldn't complete the requested write operation within the given timeout and following the specified write concern:

pymongo.errors.WTimeoutError: operation exceeded time limit, full error: {'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}

This error indicates that the server couldn't complete an insert_many() or bulk_write() method within the given timeout and following the specified write concern:

pymongo.errors.BulkWriteError: batch op errors occurred, full error: {'writeErrors': [], 'writeConcernErrors': [{'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}], 'nInserted': 2, 'nUpserted': 0, 'nMatched': 0, 'nModified': 0, 'nRemoved': 0, 'upserted': []}

To learn more about using timeouts in PyMongo, see the following API documentation:

← Stable API